题解 AT2294【Eternal Average】
题解
首先很容易看出来,答案一定是给每个 1 和 0 配上一个
显然需要依次考虑
其实我们可以很轻易地发现,当产生进位的时候,低位处减少
还剩下
然后DP的转移就很明显了,只需要设
算答案只需要统计所有
然后就做完了。不需要前缀和优化,因为第一维不超过总操作数,故直接转移复杂度是
代码
#include<bits/stdc++.h>//JZM yyds!!
#define ll long long
#define uns unsigned
#define IF (it->first)
#define IS (it->second)
#define END putchar('\n')
using namespace std;
const int MAXN=4005;
const ll INF=1e18;
inline ll read(){
ll x=0;bool f=1;char s=getchar();
while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();}
while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();
return f?x:-x;
}
int ptf[50],lpt;
inline void print(ll x,char c='\n'){
if(x<0)putchar('-'),x=-x;
ptf[lpt=1]=x%10;
while(x>9)x/=10,ptf[++lpt]=x%10;
while(lpt)putchar(ptf[lpt--]^48);
if(c>0)putchar(c);
}
inline ll lowbit(ll x){return x&-x;}
const ll MOD=1e9+7;
int n,m,k,p;
ll dp[MAXN][MAXN][2],ans;
inline void ad(ll&a,ll b){a+=b;if(a>=MOD)a-=MOD;}
signed main()
{
n=read(),m=read(),k=read(),p=(n+m-1)/(k-1);
dp[0][0][0]=1;
for(int i=1;i<=p;i++){
for(int j=0;j<=n;j++){
dp[i][j][0]=(dp[i-1][j][0]+dp[i-1][j][1])%MOD;
for(int x=1;x<k&&x<=j;x++)
ad(dp[i][j][1],dp[i-1][j-x][1]),
ad(dp[i][j][1],dp[i-1][j-x][0]);
}
for(int j=0;j<=n;j++)
if(j%(k-1)==n%(k-1)&&((k-1)*i+1-j)<=m&&((k-1)*i+1-j)%(k-1)==m%(k-1))
ad(ans,dp[i][j][1]);
}
print(ans);
return 0;
}