列表

详情


NC20427. [SHOI2013]阶乘字符串

描述

给定一个由前n个小写字母组成的串S。 
串S是阶乘字符串当且仅当前n个小写字母的全排列(共n!种)都作为S的子序列(可以不连续)出现。
由这个定义出发,可以得到一个简单的枚举法去验证,但是它实在太慢了。
所以现在请你设计一个算法,在1秒内判断出给定的串是否是阶乘字符串。

输入描述

输入第1行一个整数T,表示这个文件中会有T组数据。
接下来分T个块,每块2行:
第1行一个正整数n,表示S由前n个小写字母组成。
第2行一个字符串S。

输出描述

对于每组数据,分别输出一行。每行是YES或者NO,表示该数据对应的串S是否是阶乘字符串。

示例1

输入:

2
2
bbaa
2
aba

输出:

NO
YES

说明:

【样例解释】
第一组数据中,ab这个串没有作为子序列出现。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 390ms, 内存消耗: 8700K, 提交时间: 2023-06-04 12:54:15

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
int T,n,mxb;
int f[2097152],g[460][26];
string s;

int main() {
    for (scanf("%d",&T);T;T--) {
        scanf("%d",&n);
        cin>>s;
        mxb=1<<n;
        int len=s.length();
        if (n>21) {
            printf("NO\n");
            continue;
        }
        for (int i=0;i<n;i++) g[len][i]=g[len+1][i]=len+1;
        for (int i=len;i;i--) {
            for (int j=0;j<n;j++) g[i-1][j]=g[i][j];
            g[i-1][s[i-1]-'a']=i;
        }
        memset(f,0,sizeof f);
        for (int i=1;i<mxb;i++)
            for (int j=0;j<n;j++)
                if (i&(1<<j)) f[i]=max(f[i],g[f[i^(1<<j)]][j]);
        if (f[mxb-1]<=len) printf("YES\n");
        else printf("NO\n");
    } 
}

C++(clang++ 11.0.1) 解法, 执行用时: 576ms, 内存消耗: 16908K, 提交时间: 2023-04-25 15:45:17

#include<bits/stdc++.h>
#define MAXN 505
using namespace std;	int t,n,m;char s[MAXN];
int f[MAXN][30];
int g[1<<22];
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d%s",&n,s+1);	m=strlen(s+1);
		if(n>21){
			puts("NO");
			continue;
		}
		memset(f,-1,sizeof f);
		for(int i=1;i<=m;++i){
			for(int j=0;j<n;++j)
                f[i][j]=f[i-1][j];
			f[i][s[i]-'a']=i;
		}
		for(int i=0;i<(1<<22);++i)	g[i]=m;
		for(int s=1;s<(1<<n);++s)
			for(int i=0;i<n;++i){
				if(g[s^(1<<i)]==-1){
					g[s]=-1;
					continue;
				}
				if(s&(1<<i))	g[s]=min(g[s],f[g[s^(1<<i)]][i]);
			}
		puts(g[(1<<n)-1]<0?"NO":"YES");
	}
	return 0;
}

上一题