• 正睿OI 提高 Day1T3 ZYB玩字符串(DP)


    题目链接

    设可能的答案串为p,长为len。p一定是s的一个子串且len|n。
    虽然一些p在s中可能被断成若干段,但删掉其中的若干段后,这段区间一定会被全部消掉。
    于是枚举p后,可以用f[i][j]表示区间[i,j]是否合法。len不需要整除区间长度,多余的部分要匹配p的前缀(匹配什么后缀啊,大不了从前面开始)。
    f[i][j]可以由j-1拼,即 (f[i][j]|=f[i][j-1] && s[j]==p[(l-1)/l+1] (l=j-i+1))
    也可以是j和前面构成了可消除的串,之后可以跳过这些串继续匹配,即 (f[i][j]|=f[i][j-k*len] && f[j-k*len+1][j])
    第二种转移的上界是(O(frac{n}{len}))的。
    复杂度约是(O(sum_{len|n}(n-len+1)*n^2*n/len)=O(n^4))。对p判一下重,再判字符集合法性,跑的就很快了。

    //285ms	17216kb(string怎么那么快。。)
    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <algorithm>
    #define gc() getchar()
    #define mod (20000000)
    const int N=205;
    
    int n,q[N*N],cnt[233],cnt2[233];
    bool vis[20000001],f[N][N];
    char s[N],p[N],ans[N];
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    inline int Hash(int l)
    {
    	int x=0;
    	for(int i=1; i<=l; ++i) x=(x*37+p[i]-'A')%mod;
    	return x;
    }
    void Update()
    {
    	if(ans[1]=='{') for(int i=1; i<=n; ++i) ans[i]=p[i];
    	else
    	{
    		for(int i=1; i<=n; ++i) if(p[i]>ans[i]) return;
    		for(int i=1; i<=n; ++i) ans[i]=p[i];
    	}
    }
    bool Solve(int len)
    {
    	for(int i=1; i<=n; ++i) f[i][i]=s[i]==p[1];
    	for(int l=2; l<=n; ++l)
    	{
    		for(int i=1,j; (j=i+l-1)<=n; ++i)
    		{
    			f[i][j]=0;
    			if(f[i][j-1]&&s[j]==p[(l-1)%len+1]) f[i][j]=1;
    			else
    				for(int k=1; j>=i+k*len; ++k)
    					if(f[i][j-k*len]&&f[j-k*len+1][j]) {f[i][j]=1; break;}
    		}
    	}
    	return f[1][n];
    }
    
    int main()
    {
    	for(int T=read(); T--; )
    	{
    		ans[1]='{'; int t=0;
    		scanf("%s",s+1), n=strlen(s+1);// cin>>s; s=""+s;
    		for(int i=1; i<=n; ++i) ++cnt[s[i]];
    		for(int len=1; len<=n; ++len)
    			if(!(n%len))
    			{
    				for(int l=0,val; l+len<=n; ++l)
    				{
    					for(int i=1; i<=len; ++i) p[i]=s[l+i];// p=s.substr(l+1,l+len)
    
    					for(int i=1; i<=len; ++i) ++cnt2[p[i]];
    					bool f=1;
    					for(int i='a'; i<='z'; ++i) if(cnt2[i]&&cnt[i]%cnt2[i]) {f=0; break;}//cnt2!=0。。
    					for(int i=1; i<=len; ++i) --cnt2[p[i]];
    					if(!f) continue;
    
    					if(!vis[val=Hash(len)]) vis[val]=1, q[++t]=val;
    					else continue;
    
    					if(Solve(len)) Update();
    				}
    				if(ans[1]!='{') {ans[len+1]='', puts(ans+1); break;}
    			}
    		for(int i=1; i<=t; ++i) vis[q[i]]=0;
    		for(int i=1; i<=n; ++i) --cnt[s[i]];
    	}
    	return 0;
    }
    
  • 相关阅读:
    开发软件设计模型 visual studio UML
    to debug asp.net mvc4
    BeeFramework
    .net entity framework 泛型 更新与增加记录
    javascript debut trick, using the throw to make a interrupt(breakpoint) in your program
    C# dynamic
    webapi
    C# async / await
    NYoj 613 免费馅饼
    洛谷P1056:排座椅(贪心)
  • 原文地址:https://www.cnblogs.com/SovietPower/p/9543090.html
Copyright © 2020-2023  润新知