0
点赞
收藏
分享

微信扫一扫

CF1561D Up the Strip (整除分块 dp 因子)


Codeforces Round #740 (Div. 2, based on VK Cup 2021 - Final (Engine))

D1. Up the Strip (simplified version)

D2. Up the Strip

题意:

给出一个数,每次有两种操作,设为当前数字

  • 选择
  • 选择(向下取整)

问从变为的方案数。

思路:

  • 假设表示从变到的方案数,那么
    前一项表示通过减法到达,后一项表示通过除法到达
    这样的复杂度是的,考虑能够怎么优化。
  • 可以用前缀和优化,每次加上就行。
    后面一项,由于每次都是向下取整,真正的除数只有个,可以用整除分块来做,每次维护因子能够影响到的区间。时间复杂度
    ​​​学习链接​​

for(int l=2,r;l<=i;l=r+1){
r=i/(i/l);
dp[i]=(dp[i]+(r-l+1)*dp[i/l]%mod)%mod;
}

  • 这个复杂度过显然不大行,考虑进一步的优化。
    看看是否能从后继状态转移过来,比如当枚举到时,除数为,那么就可以通过除到达
    进一步的扩展,对于的每个除数,都能够通过中的数除到达
    可以枚举倍数,并且维护后缀和。时间复杂度

for(int j=2;j*i<=n;j++){//(i*j)/j=i,所以i*j可以转移到i
int r=min(n,(ll)i*j+j-1);//右边界
dp[i]=(dp[i]+sum[i*j]-sum[r+1]+mod)%mod;//后缀和
}

代码:

const int maxn=2e5+10;

ll n,dp[maxn],mod,sum[maxn];

int main(){
n=read,mod=read;
dp[1]=1;dp[2]=2;
sum[1]=1,sum[2]=3;
rep(i,3,n){
dp[i]=(dp[i]+sum[i-1])%mod;
for(int l=2,r;l<=i;l=r+1){
r=i/(i/l);
dp[i]=(dp[i]+(r-l+1)*dp[i/l]%mod)%mod;
//cout<<l<<" "<<r<<" "<<dp[i]<<endl;
}
sum[i]=(sum[i-1]+dp[i])%mod;
}
/*rep(i,1,n){
cout<<i<<" "<<dp[i]<<endl;
}*/
printf("%lld\n",dp[n]);
return 0;
}

const int maxn=4e6+10;

ll n,dp[maxn],mod,sum[maxn];

int main(){
n=read,mod=read;
dp[n]=sum[n]=1;
per(i,n-1,1){
dp[i]=sum[i+1];
//sum[i]=(sum[i+1]+dp[i])%mod;
for(int j=2;j*i<=n;j++){
int r=min(n,(ll)i*j+j-1);
dp[i]=(dp[i]+sum[i*j]-sum[r+1]+mod)%mod;
}
sum[i]=(sum[i+1]+dp[i])%mod;
}
write(dp[1]);
return 0;
}

​​参考​​​ 昨晚比赛结束了看群里的讨论,两个题本质是的转移方式

CF1561D Up the Strip (整除分块 dp 因子)_取整_37


好有道理~


举报

相关推荐

0 条评论