题目

题目大意

给你一个字符串,判断这个字符串是否为“阶乘字符串”。

就是子序列包含字符集的全排列的字符串。

n≤26n\leq 26n≤26 ∣S∣≤450|S|\leq 450∣S∣≤450


思考历程

首先,设toi,chto_{i,ch}toi,ch​表示iii后面遇到的第一个chchch(字符)的位置。

这个东西很好预处理。搞出之后可以看成一张图。

那么我们就可以搞出最裸的暴力:枚举全排列,在图上跑,找一找是否有这样的路径。

显然,当前选的字母一定是越早越好,这样后面就能有更多的选择。所以这个方法是正确的。

从000开始在图上跑,每次走没有走过的字母,直至走出一条长度为nnn的路径。显然图上的每一条这样的路径都是唯一的。

于是我就试着求出这些路径条数,即为子序列包含的全排列字符串的个数。

状压DP:设fi,sf_{i,s}fi,s​表示到iii,出现过的字符的集合为sss的方案。

这样跑一跑显然是会超时的。所以我就试着折半搜索,大大减少了时间复杂度。

但是还是有点大……其中sss还比较难存,所以我打了map

然而最终……30分……

和人家暴力的分数一模一样……

应该是常数过大吧……


正解

也是状压DP,设fsf_{s}fs​表示sss集合中的字符的全排列全部出现时的最前的位置。

转移的时候枚举k∈Sk\in Sk∈S,然后从fs−{k}f_{s-\{k\}}fs−{k}​转移过来,方程显然。

预处理的那个数组还是要的。

但是2262^{26}226很大……

有个很强大的结论:如果n>21n>21n>21,则450450450的长度以内没有答案。

具体证明……我不会,网上也没有……

我只知道最短长度是O(n2)O(n^2)O(n2)级别的,但是不知道怎么求……

所以应该预估一下时间复杂度,发现跑不过去,大胆猜想,从而得出这个结论


代码

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>
#define INF 0x7f7f7f7f
int n,len;
char lis[453];
int to[453][26];
int f[1<<21|1];
int main(){
freopen("in.txt","r",stdin);
int T;
scanf("%d",&T);
while (T--){
scanf("%d%s",&n,lis+1);
if (n>21){
printf("NO\n");
continue;
}
len=strlen(lis+1);
memset(to,0,sizeof to);
for (int i=0;i<=len;++i){
for (int j=i+1,k=0;j<=len && k<n;++j)
if (!to[i][lis[j]-'a'])
to[i][lis[j]-'a']=j,k++;
for (int j=0;j<n;++j)
if (!to[i][j])
to[i][j]=INF;
}
memset(f,0,sizeof f);
f[0]=0;
for (int i=1;i<(1<<n);++i)
for (int j=0;j<n;++j)
if (i>>j&1)
f[i]=(f[i^1<<j]==INF?INF:max(f[i],to[f[i^1<<j]][j]));
if (f[(1<<n)-1]==INF)
printf("NO\n");
else
printf("YES\n");
}
return 0;
}

总结

论大胆猜想的重要性……

[JZOJ3293] 【SHTSC2013】阶乘字符串的更多相关文章

  1. 【JZOJ3293】【BZOJ4416】【luoguP3989】阶乘字符串

    description 给定一个由前n个小写字母组成的串S. 串S是阶乘字符串当且仅当前n个小写字母的全排列(共n!种)都作为S的子序列(可以不连续)出现. 由这个定义出发,可以得到一个简单的枚举法去 ...

  2. 洛谷 P3989 [SHOI2013]阶乘字符串 解题报告

    P3989 [SHOI2013]阶乘字符串 题目描述 给定一个由前\(n(\le 26)\)个小写字母组成的串\(S(|S|\le 450)\).串\(S\)是阶乘字符串当且仅当前 \(n\) 个小写 ...

  3. BZOJ 4416 【SHOI2013】 阶乘字符串

    题目链接:阶乘字符串 又是一道不会做的题……看了题解后我被吓傻了…… 首先我们可以有一个显然的\(O(2^nn)\)的做法.我们先预处理出\(g_{i,j}\)表示字符串中\(i\)号位置开始第一个\ ...

  4. [SHOI2013]阶乘字符串

    题目描述 给定一个由前\(n\)个小写字母组成的串\(S\). 串\(S\)是阶乘字符串当且仅当前\(n\)个小写字母的全排列(共\(n!\)种)都作为\(S\)的子序列(可以不连续)出现. 由这个定 ...

  5. BZOJ4416: [Shoi2013]阶乘字符串

    可以大胆猜想n>21时无解,至于依据,不开O2,1s,n<=21刚好能卡过去= = 并不会证= = #include<cstdio> void up(int& a,in ...

  6. BZOJ4416 [Shoi2013]阶乘字符串 【序列自动机 + 状压dp】

    题目链接 BZOJ4416 题解 建立序列自动机,即预处理数组\(nxt[i][j]\)表示\(i\)位置之后下一个\(j\)出现的位置 设\(f[i]\)表示合法字符集合为\(i\)的最短前缀,枚举 ...

  7. [BZOJ4416][SHOI2013]阶乘字符串(子集DP)

    怎么也没想到是子集DP,想到了应该就没什么难度了. 首先n>21时必定为NO. g[i][j]表示位置i后的第一个字母j在哪个位置,n*21求出. f[S]表示S的所有全排列子序列出现的最后末尾 ...

  8. BZOJ4416 SHOI2013阶乘字符串(状压dp)

    当n大到一定程度(>21)时一定无解,并不会证. 如果要取出一个排列,显然应该让每一位在序列中的位置尽量靠前.于是设f[S]表示存在S子集中这些字母所组成的所有排列的最短前缀的长度,枚举当前排列 ...

  9. [暑假的bzoj刷水记录]

    (这篇我就不信有网站来扣) 这个暑假打算刷刷题啥的 但是写博客好累啊  堆一起算了 隔一段更新一下.  7月27号之前刷的的就不写了 , 写的累 代码不贴了,可以找我要啊.. 2017.8.27upd ...

随机推荐

  1. class4_Listbox 列表部件

    最终的运行效果图: #!/usr/bin/env python# -*- coding:utf-8 -*-# --------------------------------------------- ...

  2. tensorflow TypeError: Can not convert a float32 into a Tensor or Operation

    遇到这种情况可能是你的程序中有和你定义的tensor 变量重名的其他变量名字,jishi在for循环中使用了这个名字的作为临时变量也不行.tenor 变量很娇气.坑了我一晚上的时间. 比如:x = t ...

  3. markdown开篇

    def show(): print("你好世界!") print("实习的日子还是得好好学习呀!") print("加油 各位!")

  4. Rabbit MQ 客户端 API 开发

    项目开始 第一步首先需要引入对应的 jar 包 <!-- https://mvnrepository.com/artifact/com.rabbitmq/amqp-client --> & ...

  5. sql实现取汉字大写首字母

    )) ) AS BEGIN DECLARE @py TABLE( ch ), hz1 ) COLLATE Chinese_PRC_CS_AS_KS_WS, hz2 ) COLLATE Chinese_ ...

  6. 【POJ】1426 Find The Multiple

    题目链接:http://poj.org/problem?id=1426 题意:给定一个正整数n,找一个比n大且能只由01构成的且能够被n整除的数. 题解:这个就是在后面添0和添1小心试探.一定要是添0 ...

  7. iOS组件化开发-发布私有库

    远程索引库 将远程索引库添关联到本地 pod repo 查看本地已关联仓库源 pod repo add 本地索引库名称 远程索引库仓库地址 pod repo update 索引库名称 pod repo ...

  8. 笔记:Python实现二分查找

    def search(sequence, number, lower=0, upper=None): if upper is None: upper = len(sequence) - 1 if lo ...

  9. GetOpenFilename的基本用法(文件夹实操)

    Sub 数据导入()Dim f, arr, i&, j&, k, m%, n%, p%, sh As Workbookf = Application.GetOpenFilename(f ...

  10. 【JDK】:java.lang.Integer源码解析

    本文对JDK8中的java.lang.Integer包装类的部分数值缓存技术.valueOf().stringSize().toString().getChars().parseInt()等进行简要分 ...