http://www.elijahqi.win/archives/1633
Time limit時間制限 : 2sec / Memory limitメモリ制限 : 256MB
配点 : 1400 点
問題文
長さ N の数列 a が与えられます。 1 から N までの整数の順列 p であって、次の条件を満たすものは何通りでしょうか? 109+7 で割った余りを求めてください。
各 1≤i≤N について、pi=ai または ppi=ai の少なくとも一方が成り立つ。
制約
1≤N≤105
ai は整数である。
1≤ai≤N
入力
入力は以下の形式で標準入力から与えられる。
N
a1 a2 … aN
出力
条件を満たす順列 p の個数を 109+7 で割った余りを出力せよ。
入力例 1
Copy
3
1 2 3
出力例 1
Copy
4
次の 4 通りです。
(1,2,3)
(1,3,2)
(3,2,1)
(2,1,3)
たとえば (1,3,2) は、p1=1, pp2=2, pp3=3 となっています。
入力例 2
Copy
2
1 1
出力例 2
Copy
1
次の 1 通りです。
(2,1)
入力例 3
Copy
3
2 1 1
出力例 3
Copy
2
次の 2 通りです。
(2,3,1)
(3,1,2)
入力例 4
Copy
3
1 1 1
出力例 4
Copy
0
入力例 5
Copy
13
2 1 4 3 6 7 5 9 10 8 8 9 11
出力例 5
Copy
6
Score : 1400 points
Problem Statement
You are given an integer sequence a of length N. How many permutations p of the integers 1 through N satisfy the following condition?
For each 1≤i≤N, at least one of the following holds: pi=ai and ppi=ai.
Find the count modulo 109+7.
Constraints
1≤N≤105
ai is an integer.
1≤ai≤N
Input
The input is given from Standard Input in the following format:
N
a1 a2 … aN
Output
Print the number of the permutations p that satisfy the condition, modulo 109+7.
Sample Input 1
Copy
3
1 2 3
Sample Output 1
Copy
4
The following four permutations satisfy the condition:
(1,2,3)
(1,3,2)
(3,2,1)
(2,1,3)
For example, (1,3,2) satisfies the condition because p1=1, pp2=2 and pp3=3.
Sample Input 2
Copy
2
1 1
Sample Output 2
Copy
1
The following one permutation satisfies the condition:
(2,1)
Sample Input 3
Copy
3
2 1 1
Sample Output 3
Copy
2
The following two permutations satisfy the condition:
(2,3,1)
(3,1,2)
Sample Input 4
Copy
3
1 1 1
Sample Output 4
Copy
0
Sample Input 5
Copy
13
2 1 4 3 6 7 5 9 10 8 8 9 11
Sample Output 5
Copy
6
题意:要求我们根据一个a[i]数组构造一个p[i]或者p[p[i]]=a[i] 那么可以看出我们这个新图 要么两点间跳两步或者跳一步
那么我们首先考虑用原图建边 即i->a[i] 建边 我们考虑 如何通过这样的n个节点的图 然后去构造不同的P图 然后通过乘法原理计算数量
考虑他一共有两种情况 1 环 2长脚树 我称为痞老板
对于痞老板这种情况我需要考虑能否把他的脚塞进去变成一个圆圈 分两种情况 一种是脚的长度<弧长 那么有可能有两种方法塞入 如果<=那么就只有一种方法塞入
对于环的话 我们考虑 a的奇环可能是形成两种p环
当节点数>1时我任意两个环还有可能合成一个新的偶环 两个合并的时候交点可能是新偶环上的 任意点 所以方案数就非常多 偶环不考虑合并的情况下 就只能有构成一种p环
https://atcoder.jp/img/agc008/editorial.pdf
这个是具体的官方题解 (日文&英文)都有
#include<cstdio>
#define ll long long
#define mod 1000000007
#define N 110000
inline char gc(){
static char now[1<<16],*S,*T;
if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0;char ch=gc();
while (ch<'0'||ch>'9') ch=gc();
while (ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=gc();}
return x;
}
int a[N],in[N],color[N],mark[N],cnt[N],n,foot[N];bool circle[N];
ll dp[N];
int main(){
freopen("agc.in","r",stdin);
n=read();ll ans=1;
for (int i=1;i<=n;++i) a[i]=read(),++in[a[i]];
for (int i=1;i<=n;++i){
if (color[i]) continue;int x=i;
for(;!color[x];x=a[x]) color[x]=i;
if (color[x]!=i) continue;
for (;!circle[x];x=a[x]) circle[x]=1;
}
for (int i=1;i<=n;++i) if ((circle[i]&&in[i]>2)||(!circle[i]&&in[i]>1)) {printf("0");return 0;}
//处理痞老板(基环内向树)
for (int i=1;i<=n;++i){
if (in[i]) continue;int x=i,tmp=0;
while(!circle[x]) x=a[x],tmp++;foot[x]=tmp;
}
for (int i=1;i<=n;++i){
if (!circle[i]) continue;int x=i,st=0,first=0,id=0,len=0;
while (circle[x]){
++id;circle[x]=0;
if (foot[x]){
if (!first){
st=first=id;len=foot[x];x=a[x];continue;
}else{
int numm=(foot[x]<(id-st))+(foot[x]<=(id-st));
(ans*=numm)%=mod;if (!ans) {printf("0");return 0;}st=id;x=a[x];continue;
}
}x=a[x];
}if (first){
int numm=(len<(id+first-st))+(len<=(id+first-st));
(ans*=numm)%=mod;if (!ans) {printf("0");return 0;}
}else cnt[id]++;
}
//for (int i=1;i<=n;++i) if (cnt[i]) printf("%d %d\n",i,cnt[i]);
for (int i=1;i<=n;++i){
dp[0]=1;if (!cnt[i]) continue;
if (i>1&&(i%2)){
for (int j=1;j<=cnt[i];++j) {
dp[j]=dp[j-1]*2%mod;if (j>1) (dp[j]+=dp[j-2]*(j-1)*i%mod)%=mod;
}
}else{
for (int j=1;j<=cnt[i];++j){
dp[j]=dp[j-1];if (j>1) (dp[j]+=dp[j-2]*(j-1)*i%mod)%=mod;
}
}
(ans*=dp[cnt[i]])%=mod;if (!ans){printf("0");return 0;}
}printf("%lld",ans);
return 0;
}