6833. 2020.10.24【NOIP提高A组】T3.justice

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;
}

 

posted @ 2020-10-24 22:00  zsjz_yzy  阅读(145)  评论(1)    收藏  举报