「模拟8.21」山洞(矩阵优化DP)

暴力:

正解:

考虑循环矩阵,f[i][j]表示从i点到j点的方案数

我们发现n很小,我们预处理出n次的f[i][j]

然后在矩阵快速幂中,我们要从当前的f[i][j]*f[j][k]-->fir[i][j]

但是此时的循环为三层

我们考虑转移式子的意义在0-n次从i-j,在n+1到2×n转移至j

这样此时的j-k其实可以把他看作从0开始走j-k步本质上是一样的

然后还有一个特判,就不讲了

         for(int j=0;j<n;++j)
         {             
             ff[now][j]=(ff[now][j]+ff[last][((j-i)+n)%n])%mod;
             if((((j-i)+n)%n)==(j+i)%n)continue;
             ff[now][j]=(ff[now][j]+ff[last][(j+i)%n])%mod;    
         }

代码

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 #define MAXN 4001
 4 using namespace std;
 5 int c[MAXN],f[MAXN],fir[MAXN];
 6 int n,m;
 7 const int mod=1e9+7;
 8 void cheng(int k)
 9 {
10      memset(c,0,sizeof(c));
11      if(k==1)
12      {
13         for(int i=0;i<n;++i)
14         {
15             for(int j=0;j<n;++j)
16             {
17                c[(i+j)%n]=(c[(i+j)%n]+f[j]*f[i]+mod)%mod;            
18                //if(i*2==(j+i)%n)continue;
19             }
20         }
21         for(int i=0;i<n;++i)f[i]=c[i]%mod;
22      }    
23      else
24      {
25         for(int i=0;i<n;++i)
26         {
27             for(int j=0;j<n;++j)
28             {
29                 c[(i+j)%n]=(c[(i+j)%n]+fir[j]*f[i]+mod)%mod;                
30                 //if(i*2==((j+i)%n))continue;
31             }
32         }
33         for(int i=0;i<n;++i)fir[i]=c[i]%mod;
34      }
35 }
36 void poww(int y)
37 {
38      fir[0]=1ll;
39      while(y)
40      {
41          if(y&1ll)cheng(2ll);
42          cheng(1ll);
43          y>>=1ll;
44      }
45 }
46 int ff[4ll][MAXN];int g[MAXN];
47 int now,last;int ans[MAXN];
48 signed main()
49 {
50      //freopen("text.in","r",stdin);
51      //freopen("1.out","w",stdout);
52      scanf("%lld%lld",&n,&m);
53      int now=1;int last=0;
54      ff[0][0]=1;
55      for(int i=1;i<=n;++i)
56      {
57          if(i>1)
58          {
59              swap(now,last);memset(ff[now],0,sizeof(ff[now]));
60          }
61          for(int j=0;j<n;++j)
62          {             
63              ff[now][j]=(ff[now][j]+ff[last][((j-i)+n)%n])%mod;
64              if((((j-i)+n)%n)==(j+i)%n)continue;
65              ff[now][j]=(ff[now][j]+ff[last][(j+i)%n])%mod;    
66          }
67          if(i==m%n)
68          {
69             for(int j=0;j<n;++j)
70             {
71                g[j]=ff[now][j]%mod;
72             }
73          }
74          if(i==m)
75          {
76             printf("%lld\n",ff[now][0]);
77             return 0;
78          }
79      }
80      for(int i=0;i<n;++i)
81      {
82         f[i]=ff[now][i]%mod;
83      }
84      poww(m/n);
85      for(int i=0;i<n;++i)
86      {
87          for(int j=0;j<n;++j)
88          {
89              //if(i*2==((j+i)%n))continue;
90              ans[(i+j)%n]=(ans[(i+j)%n]+(g[i]*fir[j])%mod+mod)%mod;
91          }
92      }
93      if(m%n)
94      printf("%lld\n",ans[0]%mod);
95      else printf("%lld\n",fir[0]%mod);
96 }
View Code

猜你喜欢

转载自www.cnblogs.com/Wwb123/p/11421020.html
今日推荐