dp[i][j][h][l] 表示在点 (i,j),差值为h,小A还是uim取液体的方案数(0:小A 1:uim)
转移方程:
dp[i][j][h][1]+=(dp[i-1][j][(h-a[i][j]+k)%k][0])
dp[i][j][h][1]+=(dp[i][j-1][(h-a[i][j]+k)%k][0]
dp[i][j][h][0]+=(dp[i-1][j][(h+a[i][j])%k][1])
dp[i][j][h][0]+=(dp[i][j-1][(h+a[i][j])%k][1])
初始化:dp[i][j][a[i][j]][0]=1; 一开始小A可以从任意点开始
我一开始一直在纠结A吸毒液和B吸毒液的区别 一直想不通为什么一个是+a[i][j],一个是-a[i][j],其实很简单,因为两个人是A取一次 B再取一次的 A吸毒液 相当于给整体的差值加了k B吸毒液 相当于给整体的差值减了k
// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define N 805
#define mod 1000000007
using namespace std;
int n,m,K,a[N][N],dp[N][N][18][2]; //0:小A 1:uim
typedef long long ll;
int main()
{
ios::sync_with_stdio(false);
cin.tie(NULL);cout.tie(NULL);
cin>>n>>m>>K;
K++;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
dp[i][j][a[i][j]][0]=1;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
for(int k=0;k<=K-1;k++)
{
dp[i][j][k][0]=(dp[i][j][k][0]+dp[i-1][j][(k-a[i][j]+K)%K][1])%mod;
dp[i][j][k][0]=(dp[i][j][k][0]+dp[i][j-1][(k-a[i][j]+K)%K][1])%mod;
dp[i][j][k][1]=(dp[i][j][k][1]+dp[i-1][j][(k+a[i][j])%K][0])%mod;
dp[i][j][k][1]=(dp[i][j][k][1]+dp[i][j-1][(k+a[i][j])%K][0])%mod;
}
}
}
ll ans=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
ans=(ans+ll(dp[i][j][0][1]))%mod;
}
cout<<ans<<endl;
return 0;
}
本文介绍了一种使用四维动态规划方法解决液体取样竞赛题目的算法。通过定义dp[i][j][h][l]表示在点(i,j),差值为h,不同角色取液体的方案数,实现了从任意起点开始,两人交替取液体,求最终差值为0的方案数。文章详细解析了状态转移方程,并提供了完整的代码实现。

被折叠的 条评论
为什么被折叠?



