LOJ #2252. 「ZJOI2017」多項式(倍增)

題目
思路簡單代碼毒瘤的經典簡單OI題,真的只需要會倍增

題解主要就是一句話:一個(mod2)\pmod 2意義下的多項式的平方就是每一項的指數×=2\times =2,那麼可以考慮使用遞歸形式的快速冪來利用可快速平方和乘一個原多項式的性質,又因爲需求串長度<=18<=18,所以我們可以考慮存長度爲需求串長的所有串的個數,並在倍增時簡單轉移所有串的個數,並且每次刪除最前面的若干字符來求在區間[x,nm+1][x,n*m+1]的串的個數即可得到[L,R][L,R]的個數,最後只需要考慮一下邊界情況,存最前面的2n+12n+1個字符即可。
。。。。。。

簡單轉移>->預處理即可。
邊界處理>->__int128\rm int128大法好。
限制刪除>->dp\rm dp求出倍增的每個時刻最少需要留多少位,即可保證每次都只刪除O(18)O(18)個字符。

AC Code\rm \color{silver} AC\ Code

#include<bits/stdc++.h>
#define LL long long
#define LLL __int128
using namespace std;

#define maxn 1<<19|1
LL S,SS,t,st,qy,tr[4][maxn];
int T,n,k;
LL m,L,R,F[maxn],G[maxn],*f=F,*g=G;

LL Query(LL r){
	if(r<0) return 0;
	static LL q[100],up[100];LL m=::m,Len=n,del;
	q[q[0]=1]=r,up[1]=m&1,m>>=1;
	for(;m>1;m>>=1) q[0]++,q[q[0]]=max((q[q[0]-1]+1)>>1,t),up[q[0]]=m&1;
	for(int i=0;i<=n;i++) f[st<<(t-i)&S]++;
	LLL bef=st<<(t+1),beg;
	if(::m>1) for(;q[0];q[0]--){
		swap(f,g);
		LL tg=up[q[0]],*t1=tr[0+tg*2],*t2=tr[1+tg*2];
		for(int i=0;i<(1<<(t+1));i++) if(g[i]) f[t1[i]]+=g[i],f[t2[i]]+=g[i],g[i]=0;
		Len=(Len<<1)+(tg*t),del=max(0ll,Len-q[q[0]]);
		beg=0;
		for(int i=0;i<=(t<<1|1);i++) beg|=(bef>>i&1)<<(i<<1);
		if(!tg){
			for(int i=0;i<del;i++) f[(beg>>(3*t+2-i))&S]--;
			bef=(beg>>(2*t+1-del)&SS);
		}
		else{
			bef=0; for(int i=0;i<=t;i++) if(st>>i&1) bef^=beg<<i;
			for(int i=0;i<t;i++) f[bef>>(4*t+2-i)&S]++;
			for(int i=0;i<del;i++) f[bef>>(4*t+2-i)&S]--;
			bef=(bef>>(3*t+1-del)&SS);
		}
		f[0]--,Len-=del;
	}
	LL ret = 0;
	for(int i=0;i<(1<<(t-k));i++) ret += f[i|qy];
	memset(F,0,sizeof F),memset(G,0,sizeof G);
	return ret;
}

int main(){
	for(scanf("%d",&T);T--;){
		scanf("%d%lld%d%lld%lld",&n,&m,&k,&L,&R);t=max(n,--k);
		char ch;for(;!isdigit(ch=getchar()););
		st = (ch-'0')<<t;
		for(int i=1;i<=n;i++)
			st|=(getchar()-'0')<<(t-i);
		for(;!isdigit(ch=getchar()););
		qy = (ch-'0')<<t;
		for(int i=1;i<=k;i++)	
			qy|=(getchar()-'0')<<(t-i);
		S=(1<<(t+1))-1;
		SS=(1ll<<(2*t+2))-1;
		for(LL i=0;i<(1<<(t+1));i++){
			LL v=0,e=0;
			for(int j=0;j<=t;j++) v|=(i>>j&1)<<(j<<1);
			tr[0][i] = v>>t , tr[1][i]=v>>(t-1)&S;
			for(int j=0;j<=t;j++) if(st>>j&1) e^=v<<j;
			tr[2][i] = e>>t&S, tr[3][i]=e>>(t-1)&S;
		}
		printf("%lld\n",R-L+1<k?0:Query(n*m+1-L)-Query(n*m+1-R-1+k));
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章