之前 c f cf cf的一道原题
容斥 0 / 1 0/1 0/1后发现只和 1 1 1连续段有关
枚举拆分后或卷积即可
#include
using namespace std;
#define cs const
#define pb push_back
#define pii pair
#define fi first
#define se second
#define ll long long
#define bg begin
namespace IO{
cs int rlen=1<<20|1;
char ibuf[rlen],*ib,*ob;
inline char gc(){
(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,rlen,stdin));
return (ib==ob)?EOF:*ib++;
}
inline int read(){
char ch=gc();
int res=0;bool f=0;
while(!isdigit(ch))f=ch=='-',ch=gc();
while(isdigit(ch))res=(res*10)+(ch^48),ch=gc();
return f?-res:res;
}
inline int readstring(char *s){
int top=0;char ch=gc();
while(isspace(ch))ch=gc();
while(!isspace(ch)&&ch!=EOF)s[++top]=ch,ch=gc();
s[top+1]='\0';return top;
}
}
using IO::read;
using IO::readstring;
template<typename tp>inline void chemx(tp &a,tp b){(a<b)?(a=b):0;}
template<typename tp>inline void chemn(tp &a,tp b){(a>b)?(a=b):0;}
cs int N=19,M=(1<<17)|5;
ll dp[M][N],fac[N],f[M],v[N][M],ans[M];
int a[N][N],n,lim,cnt[M];
char str[N];
vector<int>divi;
map<vector<int>,ll>mp;
inline void fwt(ll *f){
for(int mid=1;mid<lim;mid<<=1)
for(int i=0;i<lim;i+=mid<<1)
for(int j=0;j<mid;j++)
f[i+j+mid]+=f[i+j];
}
inline void ifwt(ll *f){
for(int mid=1;mid<lim;mid<<=1)
for(int i=0;i<lim;i+=mid<<1)
for(int j=0;j<mid;j++)
f[i+j+mid]-=f[i+j];
}
inline void calc(){
ll res=f[lim-1];
for(int i=0;i<lim-1;i++)res=(cnt[i^(lim-1)]&1)?res-f[i]:res+f[i];
mp[divi]=res;
}
void dfs(int num,int lst){
if(num>n)return;
if(num==n){
return calc();
}
vector<ll>pre(lim);
for(int i=0;i<lim;i++)pre[i]=f[i];
for(int i=lst;i<=n-num;i++){
for(int j=0;j<lim;j++)f[j]=pre[j]*v[i][j];
divi.pb(i),dfs(num+i,i);
divi.pop_back();
}
}
void fmt(ll *f,int lim){
for(int mid=1;mid<lim;mid<<=1)
for(int i=0;i<lim;i+=mid<<1)
for(int j=0;j<mid;j++)
f[i+j]-=f[i+j+mid];
}
int main(){
n=read(),lim=1<<n;
for(int i=0;i<n;i++){
readstring(str);
for(int j=0;j<n;j++)a[i][j]=str[j+1]-'0';
}
for(int i=1;i<lim;i++)cnt[i]=cnt[i>>1]+(i&1);
fac[0]=1;
for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i;
for(int i=0;i<n;i++)dp[1<<i][i]=1;
for(int s=1;s<lim;s++)
for(int i=0;i<n;i++)if(((s>>i)&1)&&dp[s][i]){
ll vl=dp[s][i];
for(int j=0;j<n;j++)if(!((s>>j)&1)&&a[i][j]==1)
dp[s|(1<<j)][j]+=vl;
}
for(int s=1;s<lim;s++)
for(int i=0;i<n;i++)if(dp[s][i])v[cnt[s]][s]+=dp[s][i];
f[0]=1,fwt(f);
for(int i=1;i<=n;i++)fwt(v[i]);
dfs(0,1);
for(int i=0;i<(lim>>1);i++){
vector<int>d;int cnt=0;
for(int j=0;j<n;j++){
cnt++;
if(((i>>j)&1)==0)d.pb(cnt),cnt=0;
}sort(d.bg(),d.end());
ans[i]=mp[d];
}
fmt(ans,lim>>1);
int T=read();
while(T--){
readstring(str);
int res=0;
for(int i=1;i<n;i++)res=(res*2)+(str[i]-'0');
cout<<ans[res]<<'\n';
}return 0;
}
被 z x y zxy zxy教育
考虑对 r r r以及之后所有前缀计算答案
对于一个前缀 i i i,答案就是 i − l e n + 1 i-len+1 i−len+1这样的形式
那么最后答案可以表示成 k ∗ ( r − l + 1 ) + b k*(r-l+1)+b k∗(r−l+1)+b这样
而不同的后缀只需要考虑后缀自动机 d a g dag dag上后继即可
树剖把倍增吊起来打
#include
using namespace std;
#define cs const
#define pb push_back
#define pii pair
#define fi first
#define se second
#define ll long long
#define bg begin
namespace IO{
cs int rlen=1<<20|1;
char ibuf[rlen],*ib,*ob;
inline char gc(){
(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,rlen,stdin));
return (ib==ob)?EOF:*ib++;
}
inline int read(){
char ch=gc();
int res=0;bool f=0;
while(!isdigit(ch))f=ch=='-',ch=gc();
while(isdigit(ch))res=(res*10)+(ch^48),ch=gc();
return f?-res:res;
}
inline int readstring(char *s){
int top=0;char ch=gc();
while(isspace(ch))ch=gc();
while(!isspace(ch)&&ch!=EOF)s[++top]=ch,ch=gc();
s[top+1]='\0';return top;
}
}
using IO::read;
using IO::readstring;
cs int N=800005;
int n,q;
char str[N];
int nxt[N][26],tot=1,last=1,fa[N],len[N],ps[N];
ll k[N],b[N],s[N];
inline void insert(int c,int id){
int cur=++tot,p=last;last=cur;
len[cur]=len[p]+1,ps[id]=cur;
for(;p&&!nxt[p][c];p=fa[p])nxt[p][c]=cur;
if(!p)fa[cur]=1;
else{
int q=nxt[p][c];
if(len[p]+1==len[q])fa[cur]=q;
else{
int clo=++tot;
fa[clo]=fa[q],len[clo]=len[p]+1;
memcpy(nxt[clo],nxt[q],sizeof(nxt[q]));
for(;p&&nxt[p][c]==q;p=fa[p])nxt[p][c]=clo;
fa[cur]=fa[q]=clo;
}
}
}
int buc[N],rk[N];
int sz[N],hs[N],in[N],idx[N],top[N],dfn;
inline void build(){
for(int i=1;i<=tot;i++)buc[len[i]]++;
for(int i=1;i<=tot;i++)buc[i]+=buc[i-1];
for(int i=tot;i>=1;i--)rk[buc[len[i]]--]=i;
for(int i=tot;i>=1;i--){
int u=rk[i];
k[u]=-1,b[u]=s[u]+len[u]+1;
if(fa[u])s[fa[u]]+=s[u]+len[u]-len[fa[u]];
}
for(int i=tot;i>=1;i--){
int p=rk[i];
for(int c=0;c<26;c++){
int v=nxt[p][c];
if(v){
k[p]+=k[v],b[p]+=b[v]+k[v];
}
}
}
for(int i=tot;i>=1;i--){
int u=rk[i];sz[u]++;
sz[fa[u]]+=sz[u];
if(sz[u]>sz[hs[fa[u]]])hs[fa[u]]=u;
}
for(int i=1;i<=tot;i++){
int u=rk[i];
if(!top[u]){
for(int p=u;p;p=hs[p])
idx[in[p]=++dfn]=p,top[p]=u;
}
}
}
inline ll query(int l,int r){
int le=r-l+1,u=ps[r];
while(len[fa[top[u]]]>=le)u=fa[top[u]];
l=in[top[u]],r=in[u];int res=r;
while(l<=r){
int mid=(l+r)>>1;
if(len[idx[mid]]>=le)r=mid-1,res=mid;
else l=mid+1;
}u=idx[res];
return k[u]*le+b[u];
}
int main(){
#ifdef Stargazer
freopen("lx.in","r",stdin);
#endif
n=read(),q=read();
readstring(str);
for(int i=1;i<=n;i++)insert(str[i]-'a',i);
build();
while(q--){
int l=read(),r=read();
cout<<query(l,r)<<'\n';
}return 0;
}
枚举最大值的位置可以得到一个显然的 D P DP DP方程
直接 m t t mtt mtt可过
转成点值计算可以做到更优秀
#include
using namespace std;
#define cs const
#define pb push_back
#define pii pair
#define fi first
#define se second
#define ll long long
#define bg begin
namespace IO{
cs int rlen=1<<20|1;
char ibuf[rlen],*ib,*ob;
inline char gc(){
(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,rlen,stdin));
return (ib==ob)?EOF:*ib++;
}
inline int read(){
char ch=gc();
int res=0;bool f=0;
while(!isdigit(ch))f=ch=='-',ch=gc();
while(isdigit(ch))res=(res*10)+(ch^48),ch=gc();
return f?-res:res;
}
}
using IO::read;
template<typename tp>inline void chemx(tp &a,tp b){return (a<b)?(a=b):0;}
template<typename tp>inline void chemn(tp &a,tp b){return (a>b)?(a=b):0;}
int mod;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(int a,int b){return a<b?a-b+mod:a-b;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline void Add(int &a,int b){a=a+b>=mod?a+b-mod:a+b;}
inline void Dec(int &a,int b){a=a<b?a-b+mod:a-b;}
inline void Mul(int &a,int b){a=(ll)a*b%mod;}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,Mul(a,a))(b&1)&&(Mul(res,a),1);return res;}
typedef vector<int> poly;
typedef double db;
cs int N=201;
void write(poly f){
for(int i=0;i<f.size();i++)cout<<f[i]<<" ";puts("");
}
int n,k,C[N][N];
poly f[N];
namespace Poly{
struct plx{
db x,y;
plx(db _x=0,db _y=0):x(_x),y(_y){}
inline plx operator +(cs plx &b){
return plx(x+b.x,y+b.y);
}
inline plx operator -(cs plx &b){
return plx(x-b.x,y-b.y);
}
inline plx operator *(cs plx &b){
return plx(x*b.x-y*b.y,x*b.y+y*b.x);
}
inline plx operator *(cs db &b){
return plx(x*b,y*b);
}
inline plx operator /(cs db &b){
return plx(x/b,y/b);
}
inline plx conj()cs{return plx(x,-y);}
};
cs int MM=(1<<16)|1,T=(1<<15)-1;
plx *w[17];int rev[MM];
cs db pi=acos(-1);
inline void init_rev(int lim){
for(int i=0;i<lim;i++)rev[i]=(rev[i>>1]>>1)|((i&1)*(lim>>1));
}
inline void init_w(cs int C=16){
for(int i=1;i<=C;i++)w[i]=new plx[(1<<(i-1))|1];
w[C][0]=plx(1,0);
for(int i=1,l=1<<(C-1);i<l;i++)
w[C][i]=plx(cos(i*pi/l),sin(i*pi/l));
for(int i=C-1;i;i--)
for(int j=0,l=1<<(i-1);j<l;j++)w[i][j]=w[i+1][j<<1];
}
inline void fft(plx *f,int lim,int kd){
for(int i=0;i<lim;i++)if(i>rev[i])swap(f[i],f[rev[i]]);
plx a0,a1;
for(int mid=1,l=1;mid<lim;mid<<=1,l++)
for(int i=0;i<lim;i+=mid<<1)
for(int j=0;j<mid;j++)
a0=f[i+j],a1=f[i+j+mid]*w[l][j],f[i+j]=a0+a1,f[i+j+mid]=a0-a1;
if(kd==-1){
reverse(f+1,f+lim);
for(int i=0;i<lim;i++)f[i]=f[i]/lim;
}
}
plx a[MM],b[MM],c[MM],d[MM];
inline poly mul(poly A,poly B,int mov){
int deg=A.size()+B.size()-1,lim=1;
while(lim<deg)lim<<=1;init_rev(lim);
for(int i=0;i<A.size();i++)a[i]=plx(A[i]&T,A[i]>>15);
for(int i=A.size();i<lim;i++)a[i].x=a[i].y=0,a[i]=plx();
for(int i=0;i<B.size();i++)b[i]=plx(B[i]&T,B[i]>>15);
for(int i=B.size();i<lim;i++)b[i].x=b[i].y=0,b[i]=plx();
fft(a,lim,1),fft(b,lim,1);plx da,db,dc,dd;
for(int i=0,j;i<lim;i++){
j=(lim-i)&(lim-1);
da=(a[i]+a[j].conj())*plx(0.5,0);
db=(a[j].conj()-a[i])*plx(0,0.5);
dc=(b[i]+b[j].conj())*plx(0.5,0);
dd=(b[j].conj()-b[i])*plx(0,0.5);
c[i]=(da*dc)+(da*dd*plx(0,1)),d[i]=(db*dc)+(db*dd*plx(0,1));
}poly res(deg+mov,0);
fft(c,lim,-1),fft(d,lim,-1);
for(int i=0;i<deg;i++){
ll da=(ll)(c[i].x+0.5)%mod,db=(ll)(c[i].y+0.5)%mod,dc=(ll)(d[i].x+0.5)%mod,dd=(ll)(d[i].y+0.5)%mod;
res[i+mov]=(da+(db<<15)+(dc<<15)+(dd<<30))%mod;
}return res;
}
inline poly operator *(poly a,int b){
for(int i=0;i<a.size();i++)Mul(a[i],b),assert(a[i]>=0&&a[i]<mod);
return a;
}
inline poly operator +(poly a,poly b){
if(a.size()<b.size())a.resize(b.size());
for(int i=0;i<b.size();i++)Add(a[i],b[i]),assert(a[i]>=0&&a[i]<mod);
return a;
}
}
using namespace Poly;
inline void init_c(){
for(int i=0;i<N;i++){
C[i][0]=C[i][i]=1;
for(int j=1;j<i;j++)
C[i][j]=add(C[i-1][j],C[i-1][j-1]);
}
}
inline void solve(){
f[0].pb(1);f[1].pb(0),f[1].pb(1);
for(int i=2;i<N;i++){
for(int k=0;k<(i+1)/2;k++){
f[i]=f[i]+Poly::mul(f[k],f[i-k-1],min(k+1,i-k))*mul(C[i-1][k],(k+1==i-k)?1:2);
}
}
}
int main(){
scanf("%d",&mod);
init_w(),init_c();
solve();
while(scanf("%d%d",&n,&k)!=EOF){
if(k>=f[n].size())puts("0");
else cout<<f[n][k]<<'\n';
}
}