题解 小 a 和 uim 之大逃离

题目链接

首先可以想到设状态 k1,k2 表示小 a 和小 uim 分别表示他们目前取得的得分,那么最终的答案便是 k1=k2 的时候。

但是这样设置状态的复杂度无疑是高的。并且十分浪费,所以考虑设 z 表示 k1k2 的值。那么 z=0 就是答案。

接着考虑如何处理任意起点出发,根据套路,可以设置一个超级原点,向每个点进行连边,跑 dp 即可。

fx,y,z,0/1 表示从超级原点到 (x,y),差值为 z,且现在是 小a/小uim 拿分,答案就是 i=1,j=1n,mfi,j,0,1。将超级原点设为 (0,0) 即可,为了使得第一步是小 a 取,我们将边界条件设为 f0,0,0,1=1

fx,y,z,0=fx1,y,zax,y,1+fx,y1,zax,y,1+f0,0,zax,y,1fx,y,z,1=fx1,y,z+ax,y,0+fx,y1,z+ax,y,0+f0,0,z+ax,y,0

由于两人得分要 %(k+1),所以我们将 z 转化为模意义下的即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL read() {
LL sum=0,flag=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') flag=-1; c=getchar();}
while(c>='0'&&c<='9') {sum=sum*10+c-'0'; c=getchar();}
return sum*flag;
}
const LL MOD=1e9+7;
const int N=810;
int n,m,k;
int f[N][N][20][2],a[N][N];
int To(int x) {
return (x%(k+1)+(k+1))%(k+1);
}
int main() {
cin>>n>>m>>k;
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
a[i][j]=read();
}
}
f[0][0][0][1]=1;
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++){
for(int z=0;z<=k;z++) {
f[i][j][z][1]=((f[i-1][j][To(z+a[i][j])][0]+f[i][j-1][To(z+a[i][j])][0])%MOD+f[0][0][To(z+a[i][j])][0])%MOD;
f[i][j][z][0]=((f[i-1][j][To(z-a[i][j])][1]+f[i][j-1][To(z-a[i][j])][1])%MOD+f[0][0][To(z-a[i][j])][1])%MOD;
}
}
}
LL ans=0;
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
ans=(ans+f[i][j][0][1])%MOD;
}
}
cout<<ans;
return 0;
}
posted @   2017BeiJiang  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示