NOIP模拟赛 czy的后宫

【题目描述】

czy要妥善安排他的后宫,他想在机房摆一群妹子,一共有n个位置排成一排,每个位置可以摆妹子也可以不摆妹子。有些类型妹子如果摆在相邻的位置(隔着一个空的位置不算相邻),就不好看了。假定每种妹子数量无限,求摆妹子的方案数。

【输入格式】

输入有m+1行,第一行有两个用空格隔开的正整数n、m,m表示妹子的种类数。接下来的m行,每行有m个字符1或0,若第i行第j列为1,则表示第i种妹子第j种妹子不能排在相邻的位置,输入保证对称。(提示:同一种妹子可能不能排在相邻位置)。

【输出格式】

输出只有一个整数,为方案数(这个数字可能很大,请输出方案数除以1000000007的余数。

【样例输入】

2 2

01

10

【样例输出】

7

【样例说明】

七种方案为(空,空)、(空,1)、(1、空)、(2、空)、(空、2)、(1,1)、(2,2)。

【数据范围】

20%的数据,1<n≤5,0<m≤10。

60%的数据,1<n≤200,0<m≤100。

100%的数据,1<n≤1000000000,0<m≤100。

注:此题时限1.5s是因为本评测机跑太慢,大家正常做

但写的太丑可能T一俩个点

前辈都忙着开后宫了,就我这个苦逼在弱校挣扎。。。

F[i][j]={F[i-1][k]} i表示由i个妹子组成,j代表以j结尾

用异或状态压缩

60分:

 1 #include<iostream>
 2 using namespace std;
 3 
 4 const int mod=1000000007;
 5 
 6 int n,m,ans,p=0;
 7 int F[2][101];
 8 bool D[101][101];
 9 char s[255];
10 
11 int main()
12 {
13     cin>>n>>m;
14     for(int i=1;i<=m;i++)
15     {
16         scanf("%s",s+1);
17         for(int j=1;j<=m;j++)
18             D[i][j]=s[j]-'0';
19     }
20     for(int i=0;i<=m;i++) F[0][i]=1;
21     for(int i=2;i<=n;i++)
22     {
23         p^=1;
24         for(int j=0;j<=m;j++)
25         {
26             F[p][j]=0;
27             for(int k=0;k<=m;k++)
28                 if(!D[j][k])
29                     F[p][j]=(F[p][j]+F[p^1][k])%mod;
30         }
31     }
32     for(int i=0;i<=m;i++)
33         ans=(ans+F[p][i])%mod;
34     cout<<ans<<endl;
35     return 0;
36 }

100分要用矩阵乘法配合图论来做

f[i][k]表示从i到k的路径条数,即以第i盆花开始,第k盆花结束的摆法有多少种

那么f[i][k]=Σ(f[i][j]*f[j][k])

即f=f*gn

配合快速幂

最后ans=Σ(f[i][0])

 1 #define LL long long
 2 
 3 #include<iostream>
 4 #include<cstring>
 5 using namespace std;
 6 
 7 const int MAXN=105;
 8 const int mod=1000000007;
 9 
10 struct MAT
11 {
12     LL mat[MAXN][MAXN];
13 }f,g;
14 LL n,m,ans;
15 char ch[255];
16 
17 MAT mult(MAT a,MAT b)
18 {
19     MAT t;
20     memset(t.mat,0,sizeof(t.mat));
21     for(int i=0;i<=m;i++)
22         for(int j=0;j<=m;j++)
23             if(a.mat[i][j])
24                 for(int k=0;k<=m;k++)
25                     t.mat[i][k]=(t.mat[i][k]+a.mat[i][j]*b.mat[j][k])%mod;
26     return t;
27 }
28 
29 void modexp(int b)
30 {
31     while(b)
32     {
33         if(b&1) f=mult(f,g);
34         g=mult(g,g);
35         b>>=1;
36     }
37 }
38 
39 int main()
40 {
41     cin>>n>>m;
42     for(int i=1;i<=m;i++)
43     {
44         scanf("%s",ch+1);
45         for(int j=1;j<=m;j++)
46             if(ch[j]=='0') g.mat[i][j]=1;
47     }
48     for(int i=0;i<=m;i++)
49     {
50         g.mat[0][i]=g.mat[i][0]=1;
51         f.mat[i][i]=1;
52     }
53     modexp(n);
54     for(int i=0;i<=m;i++)
55         ans=(ans+f.mat[i][0])%mod;
56     cout<<ans<<endl;
57     return 0;
58 }
原文地址:https://www.cnblogs.com/InWILL/p/5998247.html