题目
传送门
在方格里起点终点任取,两个人绑在一起轮流取数,问有多少种方案可以使两个人取得的数在 %
k
k
下相等
题解
其实这道题是没有思路的。看了题解。
f[i][j][p][k]
f
[
i
]
[
j
]
[
p
]
[
k
]
表示在
(i,j)
(
i
,
j
)
处,两个人取的数之差为
p
p
.此时是第个人取;
初始化:
f[i][j][a[i][j]modk][0]=1
f
[
i
]
[
j
]
[
a
[
i
]
[
j
]
m
o
d
k
]
[
0
]
=
1
令
n1=(p+a[i][j])modK
n
1
=
(
p
+
a
[
i
]
[
j
]
)
m
o
d
K
n2=(p−a[i][j]+K)modK
n
2
=
(
p
−
a
[
i
]
[
j
]
+
K
)
m
o
d
K
状态转移方程:
f(i,j,p,0)=f(i+1,j,n1,1)+f(i,j+1,n1,1)
f
(
i
,
j
,
p
,
0
)
=
f
(
i
+
1
,
j
,
n
1
,
1
)
+
f
(
i
,
j
+
1
,
n
1
,
1
)
f(i,j,p,1)=f(i+1,j,n2,0)+f(i,j+1,n2,0)
f
(
i
,
j
,
p
,
1
)
=
f
(
i
+
1
,
j
,
n
2
,
0
)
+
f
(
i
,
j
+
1
,
n
2
,
0
)
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#define ll long long
using namespace std;
const int maxn=1000;
const int mod=1e9+7;
int n,m,k,a[maxn][maxn];
int f[maxn][maxn][20][2];
int main()
{
scanf("%d%d%d",&n,&m,&k);
k++;
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++)
{
scanf("%d",&a[i][j]);
f[i][j][ a[i][j]%k ][0]=1;
}
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++)
for (int p=0; p<k; p++)
{
int n1=(p+a[i][j])%k;
int n2=(p-a[i][j]+k) %k;
f[i][j][p][0]=(f[i][j][p][0]+f[i-1][j][n2][1]+f[i][j-1][n2][1]) %mod;
f[i][j][p][1]=(f[i][j][p][1]+f[i-1][j][n1][0]+f[i][j-1][n1][0]) %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;
printf("%lld",ans);
return 0;
}
总结
不能总是看着题解写DP