CSP-201409

  前三题代码并未保存。

 

 

 

问题描述

试题编号: 201409-5
试题名称:

拼图(100/100)

时间限制: 3.0s
内存限制: 256.0MB
问题描述:
问题描述
  给出一个n×m的方格图,现在要用如下L型的积木拼到这个图中,使得方格图正好被拼满,请问总共有多少种拼法。其中,方格图的每一个方格正好能放积木中的一块。积木可以任意旋转。
输入格式
  输入的第一行包含两个整数n, m,表示方格图的大小。
输出格式
  输出一行,表示可以放的方案数,由于方案数可能很多,所以请输出方案数除以1,000,000,007的余数。
样例输入
6 2
样例输出
4
样例说明
  四种拼法如下图所示:
评测用例规模与约定
  在评测时将使用10个评测用例对你的程序进行评测。
  评测用例1和2满足:1<=n<=30,m=2。
  评测用例3和4满足:1<=n, m<=6。
  评测用例5满足:1<=n<=100,1<=m<=6。
  评测用例6和7满足:1<=n<=1000,1<=m<=6。
  评测用例8、9和10满足:1<=n<=10^15,1<=m<=7。

 

直接轮廓线可以拿到70.

正解应该是矩阵幂,但暂时没想到如何推导矩阵a[S1][S2]表示上一行S1->当前行S2转移。

 正解在下方

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define LL long long
 5 #define inf 0x3f3f3f3f
 6 #define pii pair<int,int>
 7 #define pb push_back
 8 #define all(v) (v.begin(),v.end())
 9 #define mp make_pair
10 const LL mod=1000000007;
11 LL f[2][(1<<8)+5];
12 LL n,m;
13 int biti(int k,int i){
14     return ((k>>i)&1);
15 }
16 int main()
17 {
18     cin>>n>>m;
19     int cur=0,all=(1<<(m+1));
20     f[cur][0]=1;
21     for(int i=1;i<=n;++i){
22         for(int j=1;j<=m;++j){
23             cur^=1;
24             memset(f[cur],0,sizeof(f[cur]));
25         for(int k=0;k<all;++k){
26 
27         if(i==1||(i==2&&j==1)||biti(k,m))
28         (f[cur][(k<<1)&(all-1)]+=f[cur^1][k])%=mod;
29         if(i!=1 && j!=1 ){
30             if(biti(k,0)==0 && biti(k,m)==0){
31                 (f[cur][(k<<1)|3]+=f[cur^1][k])%=mod;
32             }
33             if(biti(k,0)==0 && biti(k,m-1)==0 && biti(k,m)==1){
34                 (f[cur][(k<<1)&(all-1)|3|(1<<m)]+=f[cur^1][k])%=mod;
35             }
36             if(biti(k,m)==0 && biti(k,m-1)==0){
37                 (f[cur][(k<<1)|1|(1<<m)]+=f[cur^1][k])%=mod;
38             }
39         }
40         if(i!=1 && j!=m && ( biti(k,m)==1 ||i==2&&j==1) &&biti(k,m-1)==0 && biti(k,m-2)==0){
41             (f[cur][(k<<1)&(all-1)|1|(3<<(m-1))]+=f[cur^1][k])%=mod;
42         }
43 
44         }
45         }
46     }
47     cout<<f[cur][all-1]<<endl;
48     return 0;
49 }

 

 

 正解为矩阵快速幂:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define LL long long
 5 #define inf 0x3f3f3f3f
 6 #define pii pair<int,int>
 7 #define pb push_back
 8 #define all(v) (v.begin(),v.end())
 9 #define mp make_pair
10 
11 
12 const LL mod=1000000007;
13 int biti(int n,int i){return ((n>>i)&1) ;}
14 LL all,N,M;
15 LL a[(1<<7)][(1<<7)],res[(1<<7)][(1<<7)],temp[(1<<7)][(1<<7)];
16 void dfs(int S1,int S,int S2){
17     if(S==all){
18         a[S1][S2]++;
19         return;
20     }
21     for(int i=0;i<M;++i){
22         if(biti(S,i))continue;
23         if(i<M-1&&!biti(S2,i)&&!biti(S2,i+1))dfs(S1,(S|(1<<i)),(S2|(3<<i)));
24         if(i>0&&!biti(S2,i)&&!biti(S2,i-1))dfs(S1,(S|(1<<i)),(S2|(3<<(i-1))));
25 
26         if(i<M-1&&!biti(S,i+1)&&!biti(S2,i))dfs(S1,(S|(3<<i)),(S2|(1<<i)));
27         if(i<M-1&&!biti(S,i+1)&&!biti(S2,i+1))dfs(S1,(S|(3<<i)),(S2|(1<<(i+1))));
28         break;//这里的break很关键,否则会算重
29     }
30 }
31 void mul(LL a[][(1<<7)],LL b[][(1<<7)],int sz=(1<<M)){// a<-a*b
32     for(int i=0;i<sz;++i){
33         for(int j=0;j<sz;++j){ temp[i][j]=0;
34             for(int k=0;k<sz;++k){
35                 temp[i][j]=(temp[i][j]+a[i][k]*b[k][j])%mod;
36             }
37         }
38     }
39     for(int i=0;i<sz;++i)
40         for(int j=0;j<sz;++j)a[i][j]=temp[i][j];
41 }
42 void qpow(){
43     LL n=N;
44     for(int i=0;i<=all;++i)res[i][i]=1;
45     while(n){
46         if(n&1)mul(res,a);
47         n>>=1;
48         mul(a,a);
49     }
50 }
51 int main()
52 {
53     cin>>N>>M;
54     all=(1<<M)-1;
55     for(int i=0;i<=all;++i)dfs(i,i,0);
56     qpow();
57     cout<<res[all][all]<<endl;//f(0,all)=1,f(n)=f(0)*aN 
58     return 0;
59 }

 

-

 

 

posted @ 2020-01-04 17:34  *zzq  阅读(181)  评论(0编辑  收藏  举报