【AtCoder】【AGC009E】Eternal Average

探讨了在给定数量的0和1中,通过特定的K进制数操作组合不同平均值的方法。该文介绍了一种动态规划的解决方案,用于计算所有可能的有效最终状态的数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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次的情况下被组合出,当且仅当sm(modK1)s≡m(modK−1)(s为每一位的和),

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

枚举我们组合出的K进制数有几位(最后一个不为0的位置),设有i位,
fi,jfi,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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值