• 【JZOJ3293】【BZOJ4416】【luoguP3989】阶乘字符串


    description

    给定一个由前n个小写字母组成的串S。

    串S是阶乘字符串当且仅当前n个小写字母的全排列(共n!种)都作为S的子序列(可以不连续)出现。

    由这个定义出发,可以得到一个简单的枚举法去验证,但是它实在太慢了。所以现在请你设计一个算法,在1秒内判断出给定的串是否是阶乘字符串。


    analysis

    • 状压(DP)

    • 不知道为什么(22)个字母或以上的都不合法

    • (f[S])表示(S)状态中为(1)的字母的全排列全都出现过的最前位置

    • 转移就是在某个全排列的末尾插上一个新字母,枚举新字母转移

    • 先预处理出每个位置到某下一字母的最前位置,就可以容易地(DP)


    code

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define MAXN 2100000
    #define INF 1000000007
    #define ll long long
    #define fo(i,a,b) for (ll i=a;i<=b;++i)
    #define fd(i,a,b) for (ll i=a;i>=b;--i)
    
    using namespace std;
    
    ll f[MAXN];
    ll g[500][26];
    char st[500];
    ll n,T,len;
    
    inline ll read()
    {
    	ll x=0,f=1;char ch=getchar();
    	while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
    	while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
    	return x*f;
    }
    inline ll max(ll x,ll y){return x>y?x:y;}
    int main()
    {
    	freopen("T2.in","r",stdin);
    	T=read();
    	while (T--)
    	{
    		n=read(),scanf("
    %s",st+1);
    		if (n>21){printf("NO
    ");continue;}
    		len=strlen(st+1);
    		fo(i,0,n-1)g[len][i]=g[len+1][i]=len+1;
    		fd(i,len-1,0)
    		{
    			fo(j,0,n-1)g[i][j]=g[i+1][j];
    			g[i][st[i+1]-'a']=i+1;
    		}
    		memset(f,0,sizeof(f));
    		fo(status,1,(1<<n)-1)
    		{
    			fo(i,0,n-1)if (status&(1<<i))
    			f[status]=max(f[status],g[f[status^(1<<i)]][i]);
    		}
    		printf(f[(1<<n)-1]==len+1?"NO
    ":"YES
    ");
    	}
    	return 0;
    }
    
  • 相关阅读:
    oracle 11g 中 (oracle 10g) crsctl 的 替换命令
    BZOJ 2792 Poi2012 Well 二分答案
    java基础入门-多线程同步浅析-以银行转账为样例
    CF 316div2 E.Pig and Palindromes
    Linux 性能监控 —— Load Average
    UISearchBar cancel 按钮设置文本
    UISlider 设置增量
    推荐一个在线json数据格式化网站
    解决ARC下performselector-may-cause-a-leak-because-its-selector-is-unknown 警告
    UITextView 添加 pleaceholder
  • 原文地址:https://www.cnblogs.com/horizonwd/p/11121298.html
Copyright © 2020-2023  润新知