【洛谷1357】花园

原题:

 n<=1e15

首先要看清题,花圃是环形的而不是线形的

但是不妨先思考如果是线形该如何处理

如果n<=1e5做法很显然,f[i][j]表示直到第i个点状态为j的方案数,其中j是二进制压状态

然后可以发现转移都是f[i][j]+=f[i-1][k]的形式

自然想到矩阵乘方法

在转移矩阵A中,如果存在状态k能转移到状态j,那么a[k][j]为1否则为0

扫描二维码关注公众号,回复: 9401656 查看本文章

设矩阵乘的格式为AB=C,A是m阶转移方阵,B和C是m阶列向量

这样右侧列向量中b[j][1]就会乘上a[k][j](等于1),然后被加到c[k][1]上

如果a[k][j]为0则b[j][1]就不会被转移到c[k][1]上,等价于f[i-1][j]不会转移到f[i][k]

虽然矩阵乘没有交换律,但是只要每次把转移矩阵乘在最左边即可

即AB=C变成AAB=A^2B=AC,这样就能转移任意次

最后考虑怎么把线形情况扩展到环形情况

首先可以快速幂出n-m次转移的转移矩阵,然后枚举前m个物品

然后对每个枚举到的状态t,先令列向量b[t][1]=1,然后乘上转移矩阵得到答案向量C

从C向量里挑出不会和状态t冲突的后m个物品的状态,累计答案

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 #define LL long long
 5 const int mo=1000000007;
 6 int m,o;  LL n;
 7 struct mtx{
 8     LL a[32][32];
 9     mtx(){
10         for(int i=0;i<32;++i)for(int j=0;j<32;++j)
11             a[i][j]=0;
12     }
13     mtx(int x){
14         for(int i=0;i<32;++i)for(int j=0;j<32;++j)
15             a[i][j]=0;
16         for(int i=0;i<32;++i)
17             a[i][i]=1;
18     }
19     mtx operator*(mtx y){
20         mtx z;
21         for(int i=0;i<32;++i)for(int j=0;j<32;++j)
22             for(int k=0;k<32;++k)
23                 z.a[i][j]=(z.a[i][j]+a[i][k]*y.a[k][j])%mo;
24         return z;
25     }
26     void ot(){
27         for(int i=0;i<(1<<m);++i){
28             for(int j=0;j<(1<<m);++j)
29                 printf("%lld ",a[i][j]);
30             printf("\n");
31         }
32         cout<<endl;
33     }
34 }a;
35 mtx qcp(mtx x,LL y){
36     mtx z=x,bwl(1);
37     for(;y;y>>=1){
38         if(y&1)  bwl=z*bwl;
39         z=z*z;
40     }
41     return bwl;
42 }
43 bool chck(int x){
44     int bwl=0;
45     for(;x;x>>=1)  bwl+=(x&1);
46     return bwl<=o;
47 }
48 bool chck2(int x,int y){
49     for(;x;x>>=1){
50         y>>=1;
51         if(x&1)  y|=(1<<(m-1));
52         if(!chck(y))  return false;
53     }
54     return true;
55 }
56 int main(){
57     cin>>n>>m>>o;
58     for(int i=0;i<(1<<m);++i)if(chck(i)){
59         a.a[i>>1][i]=1;
60         if(chck(i>>1|(1<<(m-1))))
61             a.a[i>>1|(1<<(m-1))][i]=1;
62     }
63     mtx tmp=qcp(a,n-m);
64     LL bwl=0;
65     for(int i=0;i<(1<<m);++i)if(chck(i)){
66         mtx ans;
67         ans.a[i][0]=1;
68         ans=tmp*ans;
69         for(int j=0;j<(1<<m);++j)if(chck2(i,j))
70             bwl=(bwl+ans.a[j][0])%mo;
71     }
72     cout<<bwl;
73     /*
74     mtx tmp=qcp(a,n-1);
75     mtx ans;
76     ans.a[0][0]=1,ans.a[1<<(m-1)][0]=1;
77     ans=tmp*ans;
78     LL bwl=0;
79     for(int i=0;i<(1<<m);++i)  bwl=(bwl+ans.a[i][0])%mo;
80     cout<<bwl<<endl;
81     */
82     return 0;
83 }
View Code

猜你喜欢

转载自www.cnblogs.com/cdcq/p/12362914.html