【AtCoder】【AGC009E】Eternal Average

Description

有n个0,m个1,每次你从这里面取出K个数,取平均值后再把平均值放回去,求最后的答案有多少种取值。
保证(n+m-1)|k

Solution

把最后的答案放在K进制下考虑,
如果一个1在第x层,对答案的贡献就是在K进制下的第-x位+1,
那我们可以考虑每次把K进制数的一位+1,操作m次

如果全部为1,答案显然为1,
也就是说,如果随便操作m次,最后出来的K进制数,如果是合法的,当且仅当:接下来再操作n次,可以把原数变成1,

一种K进制数,如果可以在操作m次的情况下被组合出,当且仅当 s m ( mod K 1 ) (s为每一位的和),

那么我们就可以通过这个性质进行DP了,
为了方便,对于一个可以通过m次操作构出的K进制数,如果再进行n-1次操作即可变成0.(k-1)(k-1)…的形式(如:K=3时为0.222222,即再操作一次即可变成1),这种方案便合法,
即可以看成,两个K进制数相加变成了那种形式,
我们知道了其中一个K进制数的位数和每位之和,另一个K进制数的位数和每位之和也可得知

枚举我们组合出的K进制数有几位(最后一个不为0的位置),设有i位,
f i , j ,j表示每位之和,
转移显然,做一个前缀和即可,
因为合法性只与j有关,合法ans+=即可。

Code

#include <cstdio>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int N=5500,mo=1e9+7;
int m,n,K,ans;
int f[2][N];
int main()
{
    scanf("%d%d%d",&n,&m,&K);--n;--K;
    fo(i,1,n+m)
    {
        register int I=i&1,q=1;
        fo(j,1,m)
        {
            if(j>K)((q-=f[!I][j-K-1])<0?q+=mo:0);
            if(j%K==m%K&&(K*i-j)%K==n%K&&(K)*i-j<=n)((ans+=q)>=mo?ans-=mo:0);
            ((q+=f[!I][j])>=mo?q-=mo:0);
            f[I][j]=q;
            if(j==K)--q;
        }
    }
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/howarli/article/details/79406510