【LOJ #547】【LibreOJ β Round #7】—匹配字符串(常系数齐次线性递推+容斥+Lucas)

传送门

f [ i ] f[i] f[i]表示前 i i i个全部合法且最后一个为 0 0 0的方案数
那么可以得到 f [ i ] = ∑ j = 1 m f [ i − j ] f[i]=\sum_{j=1}^mf[i-j] f[i]=j=1mf[ij]
s s s f f f前缀和
那么有
f [ i ] = s [ i − 1 ] − s [ i − m − 1 ] f[i]=s[i-1]-s[i-m-1] f[i]=s[i1]s[im1]
s [ i ] − s [ i − 1 ] = s [ i − 1 ] − s [ i − m − 1 ] s[i]-s[i-1]=s[i-1]-s[i-m-1] s[i]s[i1]=s[i1]s[im1]
s [ i ] = 2 ∗ s [ i − 1 ] − s [ i − m − 1 ] s[i]=2*s[i-1]-s[i-m-1] s[i]=2s[i1]s[im1]
这样就有一个 O ( m ) O(m) O(m)的递推式了
多项式取模可以做到 O ( m l o g m l o g n ) O(mlogmlogn) O(mlogmlogn)

考虑如果 m m m比较大的时候
可以容斥有几段全黑串
那么有 a n s = ∑ i = 0 n m + 1 ( − 1 ) i ( n − i m i ) 2 n − ( m + 1 ) i ans=\sum_{i=0}^{\frac{n}{m+1}}(-1)^i{n-im\choose i}2^{n-(m+1)i} ans=i=0m+1n(1)i(inim)2n(m+1)i
模数很小做个 L u c a s Lucas Lucas就完了
这样是 O ( n m l o g n ) O(\frac n mlogn) O(mnlogn)
对数据分类做一下就可以了

才发现自己线性递推的板子是错的,为此调了一年

#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
    static char ibuf[RLEN],*ib,*ob;
    (ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ob==ib)?EOF:*ib++;
}
#define gc getchar
inline int read(){
    char ch=gc();
    int res=0,f=1;
    while(!isdigit(ch))f^=ch=='-',ch=gc();
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    return f?res:-res;
}
#define ll long long
#define re register
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define cs const
#define bg begin
#define poly vector<int>
#define int long long
const int mod=65537,G=3;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline void Add(int &a,int b){a=add(a,b);}
inline int dec(int a,int b){return a>=b?a-b:a-b+mod;}
inline void Dec(int &a,int b){a=dec(a,b);}
inline int mul(int a,int b){return 1ll*a*b%mod;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,a=mul(a,a))(b&1)?(res=mul(res,a)):0;return res;}
inline int Inv(int x){return ksm(x,mod-2);}
inline void chemx(int &a,int b){a<b?a=b:0;}
inline void chemn(int &a,int b){a>b?a=b:0;}
cs int C=16;
cs int N=(1<<17)+5;
namespace solve1{
	poly w[C+1];
	inline void init_w(){
		for(int i=1;i<=C;i++)w[i].resize(1<<(i-1));
		w[C][0]=1;
		int wn=ksm(G,(mod-1)/(1<<C));
		for(int i=1;i<(1<<(C-1));i++)w[C][i]=mul(w[C][i-1],wn);
		for(int i=C-1;i;i--)
		for(int j=0;j<(1<<(i-1));j++)w[i][j]=w[i+1][j<<1];
	}
	int rev[(1<<C)<<2];
	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 ntt(poly &f,int lim,int kd){
		for(int i=0;i<lim;i++)if(i>rev[i])swap(f[i],f[rev[i]]);
		for(int mid=1,l=1,a0,a1;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=mul(w[l][j],f[i+j+mid]),f[i+j]=add(a0,a1),f[i+j+mid]=dec(a0,a1);
		if(kd==-1){
			reverse(f.bg()+1,f.bg()+lim);
			for(int i=0,inv=Inv(lim);i<lim;i++)Mul(f[i],inv);
		}
	}
	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]);
		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++)Dec(a[i],b[i]);
		return a;
	}
	inline poly operator *(poly a,poly b){
		int deg=a.size()+b.size()-1,lim=1;
		if(deg<=32){
			poly c(deg,0);
			for(int i=0;i<a.size();i++)
			for(int j=0;j<b.size();j++)
			Add(c[i+j],mul(a[i],b[j]));
			return c;
		}
		while(lim<deg)lim<<=1;
		init_rev(lim);
		a.resize(lim),ntt(a,lim,1);
		b.resize(lim),ntt(b,lim,1);
		for(int i=0;i<lim;i++)Mul(a[i],b[i]);
		ntt(a,lim,-1),a.resize(deg);
		return a;
	}
	inline poly Inv(poly a,int deg){
		poly b(1,ksm(a[0],mod-2)),c;
		for(int lim=4;lim<(deg<<2);lim<<=1){
			c=a,c.resize(lim>>1);
			init_rev(lim);
			c.resize(lim),ntt(c,lim,1);
			b.resize(lim),ntt(b,lim,1);
			for(int i=0;i<lim;i++)Mul(b[i],dec(2,mul(b[i],c[i])));
			ntt(b,lim,-1),b.resize(lim);
		}b.resize(deg);return b;
	}
	inline poly operator /(poly a,poly b){
		int deg=(int)a.size()-(int)b.size()+1;
		reverse(a.bg(),a.end());
		reverse(b.bg(),b.end());
		b=Inv(b,deg),a=a*b,a.resize(deg);
		reverse(a.bg(),a.end());
		return a;
	}
	inline poly operator %(poly a,poly b){
		if(a.size()<=b.size())return a;
		a=a-(a/b)*b,a.resize(b.size()-1);return a;
	}
	inline poly ksm(poly a,ll b,poly res,cs poly &mod){
		for(;b;b>>=1,a=a*a%mod)if(b&1)res=res*a%mod;
		return res;
	}
	namespace CH{
		inline int solve(poly coef,int *a,ll k){
			int n=coef.size(),init_w();
			poly f(n),g(2),res(1,0);g[1]=res[0]=1;
			for(int i=1; i<n;i++)f[n-i-1]=dec(0,coef[i]);
			f[n-1]=1;
			res=ksm(g,k,res,f);
			int anc=0;
			for(int i=0;i<res.size();i++)Add(anc,mul(res[i],a[i+1]));
			return anc;
		}
	}
	namespace BM{
		poly r[N];
		int a[N],fail[N],del[N],cnt,n;
		inline void update(int i){
			cnt++;
			int MUL=mul(dec(a[i],del[i]),::Inv(dec(a[fail[cnt-2]],del[fail[cnt-2]])));
			r[cnt].resize(i-fail[cnt-2],0);
			r[cnt].pb(MUL);
			for(int j=1;j<r[cnt-2].size();j++)
			r[cnt].pb(mul(dec(0,r[cnt-2][j]),MUL));
			r[cnt]=r[cnt]+r[cnt-1];
		}
		inline void B_M(){
			for(int i=1;i<=n;i++){
				for(int j=1;j<r[cnt].size();j++)
				Add(del[i],mul(r[cnt][j],a[i-j]));
				if(del[i]!=a[i]){
					fail[cnt]=i;
					if(!cnt)r[++cnt].resize(i+1);
					else update(i);
				}
			}
		}
		inline int solve(int *v,int len,ll m1,ll m2){
			n=len;
			for(int i=1;i<=n;i++)a[i]=v[i-1];
			B_M();
			int f1=CH::solve(r[cnt],a,m1),f2=CH::solve(r[cnt],a,m2);
			return dec(f1,f2);
		}
	}
	int f[N*5];
	inline void main(ll n,ll m){
		f[0]=1;init_w();
		for(int i=1;i<=m*3+20;i++){
			f[i]=mul(f[i-1],2);
			if(i>m)Dec(f[i],f[i-m-1]);
		}
		cout<<BM::solve(f,3*m+21,n+1,n);
	}
}
namespace solve2{
	int fac[mod],ifac[mod];
	inline void init(){
		fac[0]=ifac[0]=1;
		for(int i=1;i<mod;i++)fac[i]=mul(fac[i-1],i);
		ifac[mod-1]=Inv(fac[mod-1]);
		for(int i=mod-2;i;i--)ifac[i]=mul(ifac[i+1],i+1);
	}
	inline int C(int n,int m){
		return n<m?0:mul(fac[n],mul(ifac[m],ifac[n-m]));
	}
	inline int Lucas(ll n,ll m){
		if(n<m)return 0;
		if(n<mod&&m<mod)return C(n,m);
		return mul(C(n%mod,m%mod),Lucas(n/mod,m/mod));
	}
	inline int calc(ll n,ll m){
		int res=0,f1=ksm(2,n%(mod-1)),f2=Inv(ksm(2,(m+1)%(mod-1)));
		for(ll i=0,lim=n/(m+1);i<=lim;i++){
			int now=mul(Lucas(n-i*m,i),f1);
			if(i&1)Dec(res,now);
			else Add(res,now);
			Mul(f1,f2);
		}
		return res;
	}
	inline void main(ll n,ll m){
		init();
		cout<<dec(calc(n+1,m),calc(n,m))<<'\n';
	}
}
signed main(){
	#ifdef Stargazer
	freopen("lx.cpp","r",stdin);
	#endif
	ll n,m;
	cin>>n>>m;
	if(m<(1<<14))solve1::main(n,m);
	else solve2::main(n,m);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值