「模拟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 }

原文地址:https://www.cnblogs.com/Wwb123/p/11421020.html

时间: 2024-08-29 17:09:00

「模拟8.21」山洞(矩阵优化DP)的相关文章

「模拟8.21」虎

正解贪心考场只骗到了70分 做法一: 现将没有限制的边缩掉然后连边, 这样我们直接采用贪心的做法,因为每个边最多只会被反一次, 那么从叶子节点向上对于一个需要修改的边没直接令他向上直到不能修改 注意处理连在lca上有两条链的现象 1 #include<bits/stdc++.h> 2 #define MAXN 2100000 3 using namespace std; 4 struct node{int to;int n;}e[MAXN]; 5 int tot,head[MAXN]; 6 i

bzoj 3120 矩阵优化DP

我的第一道需要程序建矩阵的矩阵优化DP. 题目可以将不同的p分开处理. 对于p==0 || p==1 直接是0或1 对于p>1,就要DP了.这里以p==3为例: 设dp[i][s1][s2][r]为前i列,结尾为0的有s1行(0表示女生,1表示男生),结尾为01的有s2个,结尾为011的有n-s1-s2个,有r列全是1的方案数. 状态这么复杂,看起来一点也不能用矩阵优化,但我们可以将状态(s1,s2,r)hash成整数,然后建立状态之间的转移. 收获: 这种m超过10^7的一般都要用矩阵优化,如

Codeforces Round #341 (Div. 2) E. Wet Shark and Blocks(矩阵优化DP)

题目链接:点击打开链接 题意:给n个数作为一个块,有b个块,从其中若干个中选择数,每个块只能选一个数,最后组成一个数模x等于k的方法数. 思路:很容易想到这样一个DP方程 : 用dp[i][j]表示现在i位,余数是j.那么dp[i + 1][(j * 10 + k) % x] = dp[i][j] * cnt[k],k是指枚举放1~9中哪一位. 因为b特别大,显然要矩阵优化,知道了DP方程,其实矩阵的构造特别简单. 根据矩阵相乘的规则, 其实这个矩阵就是A[j][(j*10+a[k])%x]++

BZOJ1297 [SCOI2009]迷路 【矩阵优化dp】

题目 windy在有向图中迷路了. 该有向图有 N 个节点,windy从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1. 现在给出该有向图,你能告诉windy总共有多少种不同的路径吗? 注意:windy不能在某个节点逗留,且通过某有向边的时间严格为给定的时间. 输入格式 第一行包含两个整数,N T. 接下来有 N 行,每行一个长度为 N 的字符串. 第i行第j列为'0'表示从节点i到节点j没有边. 为'1'到'9'表示从节点i到节点j需要耗费的时间. 输出格式 包含一个整数,可能的路径数

「模拟赛20180406」膜树 prufer编码+概率

题目描述 给定一个完全图,保证\(w_{u,v}=w_{v,u}\)且\(w_{u,u}=0\),等概率选取一个随机生成树,对于每一对\((u,v)\),求\(dis(u,v)\)的期望值对\(998244353\)取模. 输入 第一行一个数\(n\) 接下来\(n\)行,每行\(n\)个整数,第\(i\)行第\(j\)个整数表示\(w_{i,j}\) 输出 输出共\(n\)行,每行\(n\)个整数,第\(i\)行第\(j\)个整数表示\(dis(i,j)\)的期望值 样例 样例输入 4 0 1

「模拟赛20191019」B 容斥原理+DP计数

题目描述 将\(n\times n\)的网格黑白染色,使得不存在任意一行.任意一列.任意一条大对角线的所有格子同色,求方案数对\(998244353\)取模的结果. 输入 一行一个整数\(n\). 输出 一行一个整数表示答案对\(998244353\)取模的值. 样例 样例输入 3 样例输出 32 数据范围 对于\(100\%\)的数据,\(1\leq n\leq 300\). 比第一题难了不知道多少-- 这种东西怎么看都是容斥嘛. 我们先考虑对角线没有限制的情况: 枚举行和列有多少个是同色的,

bzoj1009 GT考试 (kmp+矩阵优化dp)

设f[i][j]是到第i位 已经匹配上了j位的状态数 然后通过枚举下一位放0~9,可以用kmp处理出一个转移的矩阵 然后就可以矩阵快速幂了 1 #include<bits/stdc++.h> 2 #define pa pair<int,int> 3 #define CLR(a,x) memset(a,x,sizeof(a)) 4 using namespace std; 5 typedef long long ll; 6 const int maxm=22; 7 8 inline

Codeforces 351C Jeff and Brackets 矩阵优化DP

题意:你要在纸上画一个长度为n * m的括号序列,第i个位置画左括号的花费是a[i % n], 画右括号的花费是b[i % n],问画完这个括号序列的最小花费.n <= 20, m <= 1e7 思路:如果不管n和m的限制,这个题很好做,设dp[i][j]是到i位置,平衡因子是j的花费,dp[i][j] = min(dp[i - 1][j - 1] + a[i], dp[i - 1][j + 1] + b[i]),但是这样n * m到2e8级别,这是我们无法承受的.不过,我们可以发现一个性质:

poj3734 Blocks[矩阵优化dp or 组合数学]

Blocks Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6578   Accepted: 3171 Description Panda has received an assignment of painting a line of blocks. Since Panda is such an intelligent boy, he starts to think of a math problem of paint