P8340 题解
dAniel_lele · · 题解
不需要每次减半的做法。(?)
首先充要条件显然是
考虑容斥,选定一些
注意到
先考虑计算
接下来考虑带上选定我们该如何设计 dp 状态。我们希望在每次选定之前都有 dp 某一维等于真实的
还有最后一个问题:最后一个选定的怎么办。我们发现在最后一个选定之后的部分我们可以直接忽略,也就是贡献是
由于他不让开
#include <bits/stdc++.h>
#define mid ((l+r)>>1)
#define lowbit(i) (i&(-i))
using namespace std;
int mod;
inline void add(int &i,int j){
i+=j;
if(i>=mod) i-=mod;
}
inline int addv(int i,int j){
i+=j;
if(i>=mod) i-=mod;
return i;
}
const int B=1000;
int dp[1005][1005];
int del[1005];
int f[1000005];
int pw2[1000005];
signed main(){
// freopen("test.in","r",stdin);
// freopen("test.out","w",stdout);
// ios::sync_with_stdio(false);
// cin.tie(0),cout.tie(0);
int n; cin>>n>>mod;
pw2[0]=1; for(int i=1;i<=1000000;i++) pw2[i]=addv(pw2[i-1],pw2[i-1]);
for(int i=1;i<=B;i+=2) dp[0][i]=1;
f[0]=1;
int ans=pw2[n-1];
for(int i=1;i<n;i++){
int p=i%B;
memset(dp[p],0,sizeof(dp[p]));
del[0]=p;
for(int j=1;j<=B;j++){
int x=i-j*2;
if(x%(j+1)==0) add(dp[p][j],mod-f[x/(j+1)]);
}
for(int j=1;j<=B;j++) del[j]=(del[j-1]==0)?999:del[j-1]-1;
for(int j=1;j<=B;j++) add(dp[p][j],addv(dp[del[j]][j],dp[del[j]][j+1]));
f[i]=dp[p][1];//jump
add(ans,mod-1ll*dp[p][1]*pw2[n-i-1]%mod);
}
cout<<ans;
return 0;
}