[题解] CF1750F Majority
Monke_FClBrI · · 题解
一种不容斥硬做的做法。
首先我们容易证明,一个合法的串一定可以通过若干次合并两段相邻的
接着考虑合并的过程。每个合法串可能有多种合并方法,我们钦定每次只能合并最靠左的可合并的相邻段,这样就不会算重了。考虑每个合法串的最后一次合并,一定是一个全
设
先考虑后缀初始是全
若后缀初始不全
这样就是
复杂度
代码
#include<bits/stdc++.h>
#define pb push_back
#define SZ(x) (int)(x).size()
using namespace std;
const int N=5005;
// Modint ...
int n,mod;
MI f[N][N],g[N][N];
signed main(){
ios::sync_with_stdio(0);cin.tie(0);
cin>>n>>mod;MI::setmod(mod);
f[1][0]=f[2][0]=1;
// f[i][0] <- s[i]
for(int i=3;i<=n;i++){
for(int j=1;j<=n;j++)g[i][j]=g[i-1][j];
for(int j=1;j<i-1;j++){
int L=max(1,(i+1)/2-j),R=i-j-1;
f[i][j]=R-L+1;
if(i-j*2-1>0)f[i][j]+=
g[R][i-j*2-1]-g[L-1][i-j*2-1];
f[i][j]*=f[j][0];
f[i][j]+=f[i][j-1];
}
for(int j=i-1;j<=n;j++)f[i][j]=f[i][j-1];
for(int j=1;j+i<=n;j++)g[i][j+i]+=f[i][j];
f[i][0]=f[i][i-2]+1;
}
cout<<f[n][0]<<'\n';
return 0;
}
(逃