标签:21 小写字母 状压 字符串 DP 阶乘 BZOJ4416 define
大致题意: 对于一个由前\(n\)个小写字母组成的字符串,若前\(n\)个小写字母的全排列都是该字符串的子序列,则称这个字符串为阶乘字符串。求验证给定字符串是不是阶乘字符串。
前言
每日刷题计划(2/6),算法标签:DP。
这道题的状压\(DP\)好像是挺简单的,但\(n>21\)无解这个结论没想到,看了题解也不会证,只好昧着良心过了这道题。
一个不会证的结论
首先,先扔出一个结论:\(n>21\)时答案必然为\(NO\)。
证明?一脸懵逼,完全不会。
只想吐槽题解里很多人说是因为\(C_{450}^{21}<21!\),这就更让我懵逼了,明明\(C_{450}^{21}\)比\(26!\)还要大,怎么就小于\(21!\)了......
所以,这个证明就坑在这里了吧。
状压\(DP\)
这道题的状压\(DP\)还是挺好推的。
设\(f_i\)(\(i\)是前\(n\)个小写字母的一个子集)表示至少要到字符串第\(f_i\)位才能使这部分字符串中存在子集\(i\)中所有小写字母的全排列。
考虑如何转移,可以想到,如果我们删去集合中一个元素\(j\)(设删去该元素后的集合为\(i-j\)),那么就要满足对于任意\(j\),使得在\(i-j\)这个集合中所有小写字母全排列存在之后,还有元素\(j\)。
如果我们设\(g_{i,j}\)表示字符串中第\(i\)位后第一个字符\(j\)所在的位置(如果第\(i\)位之后无\(j\),则\(g_{i,j}=strlen+1\)),那么就可以得到转移方程式:
\[f_i=max\{g_{f_{i-j},j}|j∈i\}\]
其中之所以是\(max\),是因为要对于任意\(j\)都满足。
而\(g\)的预处理应该是比较简单的,可以直接见代码。
最后如果\(n=strlen+1\),说明是\(No\),否则是\(Yes\)。
代码
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 21
#define SL 450
#define Gmax(x,y) (x<(y)&&(x=(y)))
using namespace std;
int n,p,l,f[1<<N],g[SL+5][N+5];string s;
int main()
{
RI Tt,i,j;cin>>Tt;W(Tt--)
{
if(cin>>n>>s,l=s.length(),s="#"+s,n>21) {puts("NO");continue;}//n>21直接输出No
for(i=1;i<=n;++i) g[l][i]=g[l+1][i]=l+1;//初始化g的边界
for(i=l-1;~i;--i) {for(j=1;j<=n;++j) g[i][j]=g[i+1][j];g[i][s[i+1]&31]=i+1;}//初始化g
for(p=1<<n,i=0;i^p;++i) for(f[i]=0,j=1;j<=n;++j) i&(1<<j-1)&&Gmax(f[i],g[f[i^(1<<j-1)]][j]);//动态规划
puts(f[p-1]==l+1?"NO":"YES");//判断是否可行
}return 0;
}
标签:21,小写字母,状压,字符串,DP,阶乘,BZOJ4416,define 来源: https://www.cnblogs.com/chenxiaoran666/p/BZOJ4416.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。