BZOJ4416 [Shoi2013]阶乘字符串

鬼畜题啊……

上来看错题,看成子串,n>=6直接无解,n<=5直接暴力,然后狂WA,发现看错题了

然后就跪了,只好上网找题解,然后看到了一个非常厉害的结论:当n>21的时候无解!

好像证明是当n>21的时候C(450,n)<n!?

然后我们可以f[i]表示要使得状态为i的字符的全排列都出现最少需要前多少个字符

然后与处理一下每个位置之后每个字符第一次出现在哪

然后对于一个状态i,我们枚举所有这个状态包含的字符x,假设x是最后一个,那么在他之前必须能表示出除了x以外的所有全排列,所以f[i]=max(nxt[f[i^1<<x]][x])

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<queue>
#include<map>
#include<bitset>
#include<stack>
#include<vector>
#include<set>
using namespace std;
#define MAXN 1010
#define MAXM 1010
#define INF 1000000000
#define MOD 1000000007
#define ll long long
#define eps 1e-8
int f[2500000],nxt[MAXN][26];
char s[MAXN];
int n,L,N;
int main(){
	int i,j,k;
	int tmp;
	scanf("%d",&tmp);
	while(tmp--){
		scanf("%d%s",&n,s+1);
		if(n>21){
			printf("NO\n");
			continue ;
		}
		L=strlen(s+1);
		N=1<<n;
		for(i=1;i<=L;i++){
			s[i]-='a';
		}
		for(i=0;i<=L+1;i++){
			for(j=0;j<n;j++){
				nxt[i][j]=L+1;
				for(k=i+1;k<=L;k++){
					if(s[k]==j){
						nxt[i][j]=k;
						break;
					}
				}
			}
		}
		for(i=1;i<N;i++){
			f[i]=0;
			for(j=0;j<n;j++){
				if(i&(1<<j)){
					f[i]=max(f[i],nxt[f[i^(1<<j)]][j]);
				}
			}
		}
		printf(f[N-1]<=L?"YES\n":"NO\n");
	}
	return 0;
}

/*

*/


©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页