1. 程式人生 > >小a和uim之大逃離(luogu P1373 dp)

小a和uim之大逃離(luogu P1373 dp)

math block pac clu 偶數 char sdi span lag

小a和uim之大逃離(luogu P1373 dp)

給你一個n*m的矩陣,其中元素的值在1~k內。限制只能往下和往右走,問從任意點出發,到任意點結束,且經過了偶數個元素的合法路徑有多少個。在此題中,定義在一條路徑中,第奇數個元素之和為X,第偶數個元素之和為Y。X+Y同模k+1的路徑是合法路徑。答案模1e9+7。n,m<=800,1<=k<=15。

狀態是\(f[i][j][h][0/1]\),表示第i行第j列的元素,奇數元素和X-偶數元素和Y差為h,當前在路徑中是第奇數個點或第偶數個點的方案數。

\(p1=(p-a[j]+k+1)\% (k+1)\)\(p2=(p+a[j])\%(k+1)\)

。那麽狀態轉移方程就是:\[f[i][j][p][0]=f[i][j-1][p1][1]+f[i-1][j][p1][1]+(p1?0:1)\]\[f[i][j][p][1]=f[i][j-1][p2][0]+f[i-1][j][p2][0]\]

狀壓一下即可。

#include <cctype>
#include <cstdio>
#include <cstring>
using namespace std;

const int mod=1e9+7;
const int maxn=805, maxk=20;
typedef int ia3[maxn][maxk][2
]; int n, m, k, ans, a[maxn]; ia3 fnow, fpre; void getint(int &x){ char ch; int flag=1; x=0; for (ch=getchar(); !isdigit(ch); ch=getchar()) if (ch=='-') flag=-1; for (x=ch-48; ch=getchar(), isdigit(ch);) x=x*10+ch-48; x*=flag; } int main(){ scanf("
%d%d%d", &n, &m, &k); int p1, p2; for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j){ getint(a[j]); for (int p=0; p<=k; ++p){ p1=(p-a[j]+k+1)%(k+1); //這一步若小A走 p2=(p+a[j])%(k+1); //這一步若uim走 fnow[j][p][0]=(fnow[j-1][p1][1] +fpre[j][p1][1]+(p1?0:1))%mod; fnow[j][p][1]=(fnow[j-1][p2][0] +fpre[j][p2][0])%mod; if (p==0) ans=(ans+fnow[j][p][1])%mod; } memcpy(fpre[j], fnow[j], sizeof(fnow[j])); } printf("%d\n", ans); return 0; }

小a和uim之大逃離(luogu P1373 dp)