SHOI2013 阶乘字符串
阶乘字符串
给定一个由前n个小写字母组成的串S。、
串S是阶乘字符串当且仅当前n个小写字母的全排列(共n!种)都作为S的子序列(可以不连续)出现。
由这个定义出发,可以得到一个简单的枚举法去验证,但是它实在太慢了。所以现在请你设计一个算法,在1秒内判断出给定的串是否是阶乘字符串。
N<=26,T<=5,|S|<=450
Claris的题解
最小的合法串长是O(n2)级别,所以当n>21时无解。
设g[i][j]为i后面第一个字符j的位置,没有就是m+1。
设f[S]为之前序列的集合为S,全员匹配到的最早可行位置,然后枚举最后一位进行转移,若f[(1<<n)−1]≤m则可行。
转移时取max,这样就保证了以每个字母作为末尾的排列都出现了。
时间复杂度O(nm+n2n)。
#include<bits/stdc++.h>
using namespace std;
template<class T> T read(){
T x=0,w=1;char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-') w=-w;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*w;
}
template<class T> T read(T&x){
return x=read<T>();
}
#define co const
#define il inline
typedef long long LL;
char s[460];
int nx[460][26],dp[1<<21];
void real_main(){
int n=read<int>();
scanf("%s",s+1);
if(n>21) {puts("NO");return;}
int len=strlen(s+1);
for(int i=0;i<n;++i) nx[len+1][i]=nx[len][i]=len+1;
for(int i=len-1;i>=0;--i){
for(int j=0;j<n;++j) nx[i][j]=nx[i+1][j];
nx[i][s[i+1]-'a']=i+1;
}
memset(dp,0,sizeof dp);
for(int s=1;s<1<<n;++s)
for(int i=0;i<n;++i)if(s>>i&1)
dp[s]=max(dp[s],nx[dp[s^(1<<i)]][i]);
puts(dp[(1<<n)-1]==len+1?"NO":"YES");
}
int main(){
for(int T=read<int>();T--;) real_main();
return 0;
}
静渊以有谋,疏通而知事。
浙公网安备 33010602011771号