P3989 [SHOI2013]阶乘字符串 题解

由于一些不可抗拒的原因,n22 无解。

那么只用考虑 n21 的情况即可。

由于 n 的范围缩小,导致状压又可以重新使用,所以考虑状压。

fii 中所有的集合能被表示的最小下标。

那么对于任何一位 j 如果在 i 中,那么:

fi=max(next(fij,j))其中next(x,y)表示第一个在x后面出现的字符y的下标

因为本集合中的所有情况都得满足,所以下标得取最大值。

那么我们只需预处理出来 next 即可。

从后往前枚举,本位的 next 可以由上位继承,也要取上一位,设字符串中 si+1c 那么:

nexti,j=nexti+1,j

nexti,c=i+1

预处理出来,然后状压 dp,dp 时对每个状态枚举 1 的位置即可。

详细看代码。

希望有大佬可以指明下为何 n22 无解。

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
char s[505];
int n,vis[505][26],f[1<<21];
int main()
{
	freopen("factorial.in","r",stdin);
	freopen("factorial.out","w",stdout);
	int T;
	scanf("%d",&T);
	while(T--)
	{
		memset(vis,0,sizeof(vis));
		memset(f,0,sizeof(f));
		scanf("%d",&n);
		scanf("%s",s+1);
		if(n>21)
		{
			printf("NO\n");
			continue;
		}
		int len=strlen(s+1);
		for(int i=0;i<n;i++)vis[len][i]=vis[len+1][i]=len+1;
		for(int i=len-1;i>=0;i--)
		{
			for(int j=0;j<n;j++)vis[i][j]=vis[i+1][j];
			vis[i][s[i+1]-'a']=i+1;
		}
		for(int i=0;i<1<<n;i++)
		{
			for(int j=0;j<n;j++)
			{
				if(i&(1<<j))
				{
					f[i]=max(f[i],vis[f[i^(1<<j)]][j]);
				}
			}
		}
		if(f[(1<<n)-1]!=len+1)printf("YES\n");
		else printf("NO\n");
	}
	return 0;
}
posted @   Gmt丶Fu9ture  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
点击右上角即可分享
微信分享提示