Solution
首先 x=y 时答案肯定为 1,然后讨论 x≠y 的情况。
其实可以直接把 x,y当成 1,0,因为最终合并成一个细胞,相当于在每个x,y前配个 (1/k)某,
使所有系数和为 1 ,求某些限制下,x 前的系数和不同的方案数。
那么先单单看 x ,我们把系数和看成在 k 进制下的小于 1 的小数 ( 设为 p ) ,
对于每个 x 前的 (1/k)某的系数,相当于在对应的小数位上加 1 ,
假若不存在进位,那么限制就是每个数位上的和 ( 设为s ) = n,
如果有进位,每进一位相当于将 s - ( k - 1 ) ,所以就要使 ∑c ≡ m (mod (k − 1 ) ),
那么再看 y ,就是要使系数和= 1 - p ( 那个小数 ),
假设小数有 len 位,那么 1 − p 的和 应为 (len − 1)(k − 1) + k − s = len(k − 1) − s + 1。
那么就可以设 f [ i ] [ j ] 表示到第 i 位,目前和为 j 的方案数即可,因为末尾不能为 0,所以要多开一维记一下最后一位是否为 0。
Code
#include<cstdio> #define ll long long using namespace std; const int N=3010,mo=1e9+7; int f[N][N][2]; int n,m,k,i,j,l,an; ll x,y; int main(){ freopen("justice.in","r",stdin); freopen("justice.out","w",stdout); scanf("%d%d%d%lld%lld",&n,&m,&k,&x,&y); if (x==y){printf("1"); return 0;} f[0][0][1]=1; for(i=1;i<=(n+m-1)/(k-1);++i){ for(j=0;j<=n;++j){ for(l=1;l<k;++l) if (j-l>=0) f[i][j][0]=(1ll*f[i][j][0]+f[i-1][j-l][0]+f[i-1][j-l][1])%mo; f[i][j][1]=(1ll*f[i][j][1]+f[i-1][j][1]+f[i-1][j][0])%mo; if (j%(k-1)==n%(k-1)&&(i*(k-1)-j+1)<=m&&(i*(k-1)-j+1)%(k-1)==m%(k-1)) an=(an+f[i][j][0])%mo; } } printf("%d",an); return 0; }