zoukankan      html  css  js  c++  java
  • BZOJ 3555: [Ctsc2014]企鹅QQ

    似乎大家全部都用的是hash?那我讲一个不用hash的做法吧。

    首先考虑只有一位不同的是哪一位,那么这一位前面的位上的字符一定是全部相同,后面的字符也是全部相同。首先考虑后面的字符。

    我们对n个串的反串建trie树,这样,每一个后缀就对应一个trie树上的唯一一个节点,不同的后缀对应的就是不同的节点,这样就不用hash表了。

    但是字符集很大,用trie空间太大,那么就用邻接表或map存边就好了。

    然后就是令前缀全部相同。那么我们从左到右枚举每一位,按照当前位的字符进行分治,当前位不同的就通过后缀计算贡献,相同的就放在一起,继续分治即可。

    然后就跑的飞快,目前是BZOJ rk2,Luogu rk1。

    实现的时候有很多细节,具体请参考代码。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<cctype>
    #define qmin(x,y) (x=min(x,y))
    #define qmax(x,y) (x=max(x,y))
    #define vi vector<int>
    #define vit vector<int>::iterator
    #define pir pair<int,int>
    #define fr first
    #define sc second
    #define mp(x,y) make_pair(x,y)
    #define rsort(x,y) sort(x,y),reverse(x,y)
    using namespace std;
    
    inline char gc() {
    //	static char buf[100000],*p1,*p2;
    //	return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    	return getchar();
    }
    
    template<class T>
    int read(T &ans) {
    	ans=0;char ch=gc();T f=1;
    	while(!isdigit(ch)) {
    		if(ch==EOF) return -1;
    		if(ch=='-') f=-1;
    		ch=gc();
    	}
    	while(isdigit(ch))
    		ans=ans*10+ch-'0',ch=gc();
    	ans*=f;return 1;
    }
    
    template<class T1,class T2>
    int read(T1 &a,T2 &b) {
    	return read(a)!=EOF&&read(b)!=EOF?2:EOF;
    }
    
    template<class T1,class T2,class T3>
    int read(T1 &a,T2 &b,T3 &c) {
    	return read(a,b)!=EOF&&read(c)!=EOF?3:EOF;
    }
    
    typedef long long ll;
    const int Maxn=6100000;
    const int Maxm=31000;
    const int Maxl=210;
    const int inf=0x3f3f3f3f;
    
    int to[Maxn],nxt[Maxn],first[Maxn],tot=1;
    char w[Maxn],s[Maxm][Maxl];
    int p[Maxm][Maxl],n,len,x,po[Maxl][Maxl],qq[Maxl],bj[Maxl],ans;
    int a[Maxm],siz[Maxl],b[Maxm],tn[Maxn],cnt=1;
    queue<int> q[Maxl];
    
    inline void add(int u,int v,char wi) {
    	to[tot]=v;
    	nxt[tot]=first[u];
    	w[tot]=wi;
    	first[u]=tot++;
    }
    
    void solve(int l,int r,int cur) {
    	if(l>r) return ;
    	if(cur==len) return ;
    	int cnt=0;
    	for(int i=l;i<=r;i++) {
    		int x=s[a[i]][cur];
    		q[x].push(a[i]);
    		siz[x]++;
    		if(!bj[x]) qq[++cnt]=x,bj[x]=1;
    	}
    	if(cnt==1) {
    		for(int i=1;i<=cnt;i++) bj[qq[i]]=siz[qq[i]]=0;
    		while(!q[qq[1]].empty()) q[qq[1]].pop();
    		solve(l,r,cur+1);
    	}
    	else {
    		int sxz,zhy=0;
    		for(int i=1;i<=cnt;i++) {
    			if(siz[qq[i]]>zhy) {
    				sxz=i;
    				zhy=siz[qq[i]];
    			}
    		}
    		swap(qq[cnt],qq[sxz]);
    		int las=l;po[cur][0]=las;
    		for(int i=1;i<cnt;i++) {
    			int x=qq[i],num=0;
    			while(!q[x].empty()) {
    				int now=q[x].front();
    				q[x].pop();
    				b[++num]=p[now][cur+1];
    				ans+=tn[b[num]];
    				a[las++]=now;
    			}
    			while(num) tn[b[num--]]++;
    			po[cur][i]=las;
    		}
    		while(!q[qq[cnt]].empty()) {
    			int now=q[qq[cnt]].front();
    			q[qq[cnt]].pop();
    			ans+=tn[p[now][cur+1]];
    			a[las++]=now;
    		} po[cur][cnt]=las;
    		for(int i=l;i<po[cur][cnt-1];i++) tn[p[a[i]][cur+1]]--;
    		for(int i=1;i<=cnt;i++) bj[qq[i]]=siz[qq[i]]=0;
    		for(int i=1;i<=cnt;i++)
    			solve(po[cur][i-1],po[cur][i]-1,cur+1);
    	}
    }
    
    signed main() {
    //	freopen("test.in","r",stdin);
    	read(n,len,x);
    	for(int i=1;i<=n;i++) {
    		scanf("%s",s[i]);
    		int now=1;
    		for(int j=len-1;j>=0;j--) {
    			int temp=0;
    			for(int k=first[now];k;k=nxt[k])
    				if(w[k]==s[i][j]) {
    					temp=to[k];
    					break;
    				}
    			if(!temp) add(now,++cnt,s[i][j]),temp=cnt;
    			now=temp;
    			p[i][j]=now;
    		}
    	}
    	for(int i=1;i<=n;i++) a[i]=i;
    	solve(1,n,0);
    	printf("%d
    ",ans);
    	return 0;
    }
    
    
    
    
  • 相关阅读:
    什么是socket ??
    WebView的使用
    UIWebView 使用
    UIWebView与JavaScript的交互
    iOS中UIWebView使用JS交互
    iOS app支付宝接口调用的一点总结(补充支付宝SDK&Demo下载地址)
    51单片机 按键,键盘检测
    51单片机 数码管的显示与译码器
    C51数据类型扩充定义
    STC12C5A60S2 内部AD+1602显示
  • 原文地址:https://www.cnblogs.com/shanxieng/p/10783697.html
Copyright © 2011-2022 走看看