题解
- 题目大意:给n瓶化学药品和k个盒子,每瓶化学药品和一瓶化学药品不能放在一个盒子里,求放化学药品的方案数
- 我们可以将不能放在同一个盒子的两瓶化学药品连一条边,那么就形成了一个图,而且每个点的出都只有1
- 那么考虑一下染色,一条边的两个点不能染成同一种颜色
- 其实这样的话,就可以设f[i][0/1]为第i个点,染0色或1色的方案数
- f[i][0]=(f[i-1][1]*(k-1)+f[i-1][0]*(k-2))%mo
- f[i][1]=f[i][0]
- 这个可以预处理出来
- 然后我们将每个点在哪个环求出来,在求出连通块的个数,然后ans=ans* (f[lt,1]*k%mo)%mo lt为当前循环的搜到的连通块的个数
- 求出将每个连通块的填颜色的个数相乘就求出ans
代码
1 #include <cstdio>
2 #include <iostream>
3 #include <cstring>
4 using namespace std;
5 const int inf=1000000000,mo=1000000007;
6 long long ans,a[110],d[110],tot,num,f[110][3];
7 int n,k,t;
8 int main()
9 {
10 for (scanf("%d",&t);t;t--)
11 {
12 memset(a,0,sizeof(a)); memset(d,0,sizeof(d)); memset(f,0,sizeof(f));
13 scanf("%d%d",&n,&k);
14 for (int i=0;i<=n-1;i++)
15 {
16 scanf("%lld",&a[i]);
17 d[i]=inf;
18 }
19 f[0][1]=1; f[1][0]=k-1;
20 for (int i=2;i<=n;i++)
21 {
22 f[i][0]=(f[i-1][1]*(k-1)+f[i-1][0]*(k-2))%mo;
23 f[i][1]=f[i-1][0];
24 }
25 num=0; ans=1;
26 for (int i=0;i<=n-1;i++)
27 if (d[i]==inf)
28 {
29 int x=i;
30 while (d[x]==inf) d[x]=i,x=a[x];
31 if (d[x]!=i) continue;
32 int y=x; tot=1; x=a[x];
33 while (x!=y) tot++,x=a[x];
34 ans=ans*(f[tot][1]*k%mo)%mo;
35 n-=tot;
36 }
37 for (int i=1;i<=n;i++) (ans*=(k-1))%=mo;
38 printf("%lld
",ans);
39 }
40 }