BUAA Summer Practice 2017 #1 字符串专场

https://vjudge.net/contest/262753#overview

C - Regular Number HDU - 5972

bitset temp, temp[i]=1表示 此前i个位置都能完全匹配,&=bt[x-'0']来递推

int n,a[1111][12];
char s[5000050];
int main()
{
	while(~scanf("%d",&n))
	{
		bitset<1000> bt[11];
		re(i,0,9)bt[i].reset();
		re(i,1,n)
		{
			int x;inin(x);
			re(j,1,x)
			{
				int y;inin(y);
				bt[y][i-1]=1;
			}
		}
		strin(s+1);
		int len=strlen(s+1);
		while(s[len]<'0'||s[len]>'9')len--;
		bitset<1000> temp;
		temp.reset();
		re(i,1,len)
		{
			temp<<=1;
			temp[0]=1;
			temp&=bt[s[i]-'0'];
			if(temp[n-1]==1)
			{
				fwrite(s+i-n+1,sizeof(s[0]),n,stdout);
				puts("");
			}
		}
	}
	return 0;
}

A - Password Suspects UVALive - 4126

AC自动机上DP,ans[x][y][s]表示当前在x结点,已经用了y个字符,已经含有了s集合中的子串,之后还有多少种方法。

调了半天发现没考虑输入相同的子串。


int ch[111][27],pre[111],tag[111],ed;
int n,m;
void add(char *s,int x)
{
	int temp=0;
	while(*s)
	{
		int c=(*s)-'a';
		if(!ch[temp][c])ch[temp][c]=++ed;
		temp=ch[temp][c];
		s++;
	}
	tag[temp]|=(1<<x);
}
queue<int> h;
void getpre()
{
	re(i,0,25)if(ch[0][i])h.push(ch[0][i]);
	while(!h.empty())
	{
		int x=h.front();h.pop();
		tag[x]|=tag[pre[x]];
		re(i,0,25)
		{
			if(!ch[x][i])
			{
				ch[x][i]=ch[pre[x]][i];
				continue;
			}
			int vv=ch[x][i];
			int k=pre[x];
			pre[vv]=ch[k][i];
			h.push(vv);
		}
	}
}
bool bo[105][28][1028];
LL ans[105][28][1028];
LL dfs(int x,int y,int s)
{
	if(bo[x][y][s])return ans[x][y][s];
	bo[x][y][s]=1;
	if(y==n)return ans[x][y][s]=(s==(1<<m)-1)?1:0;
	LL &aa=ans[x][y][s];
	aa=0;
	re(i,0,25)aa+=dfs(ch[x][i],y+1,s|tag[ch[x][i]]);
	return aa;
}
char ss[332];
void out(int x,int y,int s)
{
	if(y==n)
	{
		if(s==(1<<m)-1)ss[n]=0,puts(ss);
		return ;
	}
	re(i,0,25)
	{
		int vv=ch[x][i];
		if(bo[vv][y+1][s|tag[vv]]&&ans[vv][y+1][s|tag[vv]])
			ss[y]=i+'a',out(vv,y+1,s|tag[vv]);
	}	
}
int tt;
char s[122];
int main()
{
//	freopen("a.in","r",stdin);
	while(~scanf("%d%d",&n,&m))
	{
		tt++;
		if(!n)return 0;
		ed=0;
		Clear(pre,0);
		Clear(ans,0);
		Clear(bo,0);
		Clear(ch,0);
		Clear(tag,0);
		re(i,1,m)strin(s+1),add(s+1,i-1);
		getpre();
		LL ans=dfs(0,0,0);
		printf("Case %d: %lld suspects
",tt,ans);
		if(ans<=42)out(0,0,0);
	}
	return 0;
}

L - The Problem to Slow Down You UVALive - 7041

求两个字符串相同回文子串数目

构建回文树然后dfs相同结点(路径)

struct st
{
	int ch[200010][27],sum[200010],len[200010],pre[200020],ed;
	char s[200010];
	int getpre(int x,int y)
	{
		while(s[y]!=s[y-len[x]-1])x=pre[x];
		return x;
	}
	void Main()
	{
		ed=1;
		Clear(ch[0],0),Clear(ch[1],0);
		len[0]=0,len[1]=-1;
		pre[0]=1;
		strin(s+1);
		int l=strlen(s+1),temp=0;
		s[0]=-1;
		re(i,1,l)
		{
			int now=getpre(temp,i);
			if(!ch[now][s[i]-'a'])
			{
				int k=++ed;
				sum[k]=0;
				Clear(ch[k],0);
				len[k]=len[now]+2;
				pre[k]=ch[getpre(pre[now],i)][s[i]-'a'];
				ch[now][s[i]-'a']=k;
			}
			sum[temp=ch[now][s[i]-'a']]++;
		}
		rre(i,ed,0)sum[pre[i]]+=sum[i];
	}
}t[2];
LL ans;
void dfs(int t0,int t1)
{
	if(t[0].len[t0]>0)ans+=1LL*t[0].sum[t0]*t[1].sum[t1];
	re(i,0,25)if(t[0].ch[t0][i]&&t[1].ch[t1][i])dfs(t[0].ch[t0][i],t[1].ch[t1][i]);
}
int T;
int main()
{
	inin(T);int tt=T;
	while(T--)
	{
		ans=0;
		t[0].Main();
		t[1].Main();
		dfs(0,0);
		dfs(1,1);
		printf("Case #%d: %lld
",tt-T,ans);
	}
	return 0;
}

K - Om Nom and Necklace CodeForces - 526D

可以证明i-pre[i]是最短的循环节长度(B+A),然后判断是否能把i拆成k个循环节+一个长度小于循环节的串,或者直接拆成k+1个循环节,前者用二分判,后者直接判整除。

char a[1000010];
int pre[1000010];
void getpre(char *s)
{
    int k=0;int n=strlen(s+1);
    re(i,2,n)
    {
        while(k&&s[i]!=s[k+1])k=pre[k];
        if(s[i]==s[k+1])k++;
        pre[i]=k;
    }
}
int n,k;
int main()
{
	inin(n),inin(k);
	strin(a+1);
	getpre(a);
	int len=strlen(a+1);
	re(i,1,len)
	{
		int x=i-pre[i];
		if(i%x==0&&(i/x)%(k+1)==0)putchar('1');
		else 
		{
			int l=1,r=i/x,mid;
			while(l<r)
			{
				mid=(l+r)>>1;
				if(i/(mid*x)>k)l=mid+1;
				else r=mid;
			}
			if(i/(l*x)==k)putchar('1');
			else putchar('0');
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/HugeGun/p/10627229.html