有一个 H ∗ W H*W H∗W的表格, 在表格中有个车, 它开始在 ( x 1 , y 1 ) (x_1,y_1) (x1,y1)的位置,它可以移动到同一个行或同一列的其他格子,但不能原地不动。 现在,请问移动 K K K次,它恰好出现在 ( x 2 , y 2 ) (x_2,y_2) (x2,y2)的方案数。 答案可能很大,你需要 ( m o d 998244353 ) (mod998244353) (mod998244353)
比赛看题表忙忙,赛后题解脑茫茫,直到上问Depseaspary才取得真经。
这题还是老熟人dp
我们设 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示 移动 k k k次到达 第 i i i行 第 j j j列 的方案数,于是很容易想到 k − 1 k-1 k−1的第 i i i行加上的 j j j行的和减去2倍(加行算一次,加列算一次)自己(不可以停留不动),即:
f [ i ] [ j ] [ k ] = ∑ i = 1 H f [ i ] [ j ] [ k − 1 ] + ∑ j = 1 W f [ i ] [ j ] [ k − 1 ] − 2 ∗ f [ i ] [ j ] [ k − 1 ] f[i][j][k]={\sum_{i=1}^H f[i][j][k-1]}+{\sum_{j=1}^W}f[i][j][k-1]-2*f[i][j][k-1] f[i][j][k]=i=1∑Hf[i][j][k−1]+j=1∑Wf[i][j][k−1]−2∗f[i][j][k−1]
我们再设 h [ i ] [ k ] h[i][k] h[i][k]为 第 k k k次移动到达第 i i i行的方案数的和 , w [ j ] [ k ] w[j][k] w[j][k]为 第 k k k次移动到达第 j j j列的方案数的和。
f [ i ] [ j ] [ k ] = h [ i ] [ k − 1 ] + w [ j ] [ k − 1 ] − 2 ∗ f [ i ] [ j ] [ k − 1 ] f[i][j][k]=h[i][k-1]+w[j][k-1]-2*f[i][j][k-1] f[i][j][k]=h[i][k−1]+w[j][k−1]−2∗f[i][j][k−1]
设 A [ k ] A[k] A[k] IOI 表示步数为 k k k时的表格中方案数的和。
如图:
h [ i ] [ k ] = h [ i ] [ k − 1 ] ∗ W + A [ k − 1 ] − 2 ∗ h [ i ] [ k − 1 ] = ( W − 2 ) ∗ h [ i ] [ k − 1 ] + A [ k − 1 ] h[i][k]=h[i][k-1]*W+A[k-1]-2*h[i][k-1]=(W-2)*h[i][k-1]+A[k-1] h[i][k]=h[i][k−1]∗W+A[k−1]−2∗h[i][k−1]=(W−2)∗h[i][k−1]+A[k−1]
w [ j ] [ k ] w[j][k] w[j][k]也可以如上推理表示。
w [ j ] [ k ] = w [ j ] [ k − 1 ] ∗ H + A [ k − 1 ] − 2 ∗ W [ j ] [ k − 1 ] = ( H − 2 ) ∗ w [ j ] [ k − 1 ] + A [ k − 1 ] w[j][k]=w[j][k-1]*H+A[k-1]-2*W[j][k-1]=(H-2)*w[j][k-1]+A[k-1] w[j][k]=w[j][k−1]∗H+A[k−1]−2∗W[j][k−1]=(H−2)∗w[j][k−1]+A[k−1]
现在我们发现只有 A [ k ] A[k] A[k]这个小淘气还没有被宝表示出来,那我们也给 A [ k ] A[k] A[k]量身定制一套表示方案
对与 A [ k ] A[k] A[k]中每一个点 ( i , j ) (i,j) (i,j),都是由其 k − 1 k-1 k−1步时的行加列所得,那么每一行会被加 W W W次,每一列会被加 H H H次,那么每一个点就会加 H + W H+W H+W次 。
那么 A [ k ] = A [ k − 1 ] ∗ ( H + W ) A[k]=A[k-1]*(H+W) A[k]=A[k−1]∗(H+W)
因为不可以走动的老规则,所以答案应该 − 2 -2 −2。
A [ k ] = A [ k − 1 ] ∗ ( H + W − 2 ) A[k]=A[k-1]*(H+W-2) A[k]=A[k−1]∗(H+W−2)
( i , j ) (i,j) (i,j)方案数
f [ i ] [ j ] [ k ] = h [ i ] [ k − 1 ] + w [ j ] [ k − 1 ] − 2 ∗ f [ i ] [ j ] [ k − 1 ] f[i][j][k]=h[i][k-1]+w[j][k-1]-2*f[i][j][k-1] f[i][j][k]=h[i][k−1]+w[j][k−1]−2∗f[i][j][k−1]
i i i行的方案数
h [ i ] [ k ] = ( W − 2 ) ∗ h [ i ] [ k − 1 ] + A [ k − 1 ] h[i][k]=(W-2)*h[i][k-1]+A[k-1] h[i][k]=(W−2)∗h[i][k−1]+A[k−1]
j j j列的方案数
w [ j ] [ k ] = ( H − 2 ) ∗ w [ j ] [ k − 1 ] + A [ k − 1 ] w[j][k]=(H-2)*w[j][k-1]+A[k-1] w[j][k]=(H−2)∗w[j][k−1]+A[k−1]
全图总方案数
A [ k ] = A [ k − 1 ] ∗ ( H + W − 2 ) A[k]=A[k-1]*(H+W-2) A[k]=A[k−1]∗(H+W−2)
A [ 0 ] = 1 A[0]=1 A[0]=1
第0步时,只有 ( x 1 , y 1 ) (x1,y1) (x1,y1)出生点可以到达
如果 x 1 = = x 2 x1==x2 x1==x2 那么 h [ x 1 ] [ 0 ] = 1 h[x1][0]=1 h[x1][0]=1
x 1 ( x 2 ) x1(x2) x1(x2)行在没走的时候就可以到达
如果 y 1 = = y 2 y1==y2 y1==y2 那么 w [ y 1 ] [ 0 ] = 1 w[y1][0]=1 w[y1][0]=1
y 1 ( y 2 ) y1(y2) y1(y2)列在没走的时候就可以到达
如果你看数据范围的话,你会有手撕出题人的想法……
难不成我们手推这么久的光阴就要浪费了吗?
为让Depseaspary开心点老实点,我们先观察方程。
不难发现,方程中的行号和列号根本没变!
也就是说,我们没必要去开行和列的数组,更不用枚举行和列,直接求和不就完了!
#include
using namespace std;
#define ll long long
const int maxn=2e6+5,mod=998244353;
ll n,m,k,sx,sy,ex,ey;
ll f[maxn],h[maxn],w[maxn],a[maxn];
int main()
{
scanf("%lld%lld%lld%lld%lld%lld%lld",&n,&m,&k,&sx,&sy,&ex,&ey);
a[0]=1;
for(int i=1;i<=k;i++) a[i]=(a[i-1]*((n+m-2)%mod))%mod;
if(sx==ex) h[0]=1;
if(sy==ey) w[0]=1;
if(sx==ex&&sy==ey) f[0]=1;
for(int i=1;i<=k;i++) h[i]=((h[i-1]*((m-2)%mod))%mod+a[i-1])%mod;
for(int i=1;i<=k;i++) w[i]=((w[i-1]*((n-2)%mod))%mod+a[i-1])%mod;
for(int i=1;i<=k;i++) f[i]=(((h[i-1]+w[i-1])%mod)-(2*f[i-1]%mod))%mod;
printf("%lld",(f[k]+mod)%mod);//防止负数
}
在最后的最后,我愿意说一句:“Depseaspary Orz”。