【GDOI2016模拟4.23】无界单词
来源:互联网 发布:用网络漏洞怎样赚钱 编辑:程序博客网 时间:2024/06/13 02:18
Description
学过kmp吗?
一个只由a和b组成的字符串S,如果next[|S|]=0,那么这个单词就是无界的,否则就是有界的。
给出n和k,求长度为n的无界单词有多少个,和其中字典序第k小的是什么。
多组询问。
Type<=50,n<=64
Solution
很考验思维的一道题。
一般人(我)看到就想到鬼畜数论,结果正解是dp(也不算吧)
首先处理第一问。
好像很难做
正难则反。
设
一个很明显的性质,如果一个有界单词最小的前后缀相等长度为j,那么它长度为j的前缀一定是无界单词。
另一个性质,j<=i/2。
那么我们可以通过枚举j,把这一段复制到后面,剩下的任选,那么
并且这样是不会算重的。
那么第二问呢?
我们一位一位枚举,先填a,如果此时剩余的无界单词数量< k,那么这一位就必须填b,并且k要减去剩余的数量。
如何计算剩余的数量?
还是使用上面的思路。
假设前Len位已经确定,那么我们可以分类讨论。
1.len>=i
这时的字符串已经是确定的,那么只需要用kmp(暴力)就好了。
2.len<=j
这时我们复制是不会有重复的,也不会有任何影响,就像第一问的方法一样做就好了。
3.len>j&&len<=i-j
差不多,但是中间本来任选的地方也有一些是确定的,只需要改变任选的方案数成
4.len>i-j
这样的话中间就没有任选的了,并且我们复制的时候会和原来已经确定的部分重叠,hash判断是否可行。
Code
#include<cstdio>#include<cstring>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define N 65using namespace std;typedef long long ll;ll f[N],mi[N],h[N],cnt,k;int n,ty,next[N],j,ans[N],len;int hash(int x) { int y=len-x; return h[x]==h[len]-h[y]*mi[x];}ll calc(int len) { fo(i,1,len) f[i]=!next[i]; fo(i,len+1,n) { f[i]=mi[i-len]; fo(j,1,i/2) { if (j>=len) cnt=mi[i-2*j]; if (len>j&&len<=i-j) cnt=mi[i-j-len]; if (len>i-j) cnt=hash(len-i+j); f[i]-=f[j]*cnt; } } return f[n];}void push(int c) { ans[++len]=c;h[len]=h[len-1]*2+c; if (len==1) return; while (j&&ans[j+1]!=ans[len]) j=next[j]; next[len]=j+=(ans[j+1]==ans[len]);}ll work() { printf("%lld\n",calc(0));j=len=0; memset(next,0,sizeof(next)); fo(i,1,n) { int l=j;push(0); ll cnt=calc(len); if (cnt<k) len--,j=l, push(1),k-=cnt; } fo(i,1,n) printf("%c",ans[i]+'a'); printf("\n");}int main() { freopen("word.in","r",stdin); freopen("word.out","w",stdout); mi[0]=1;fo(i,1,64) mi[i]=mi[i-1]*2; for(scanf("%d",&ty);ty;ty--) scanf("%d%lld",&n,&k),work();}
0 0
- 【GDOI2016模拟4.23】无界单词
- 【GDOI2016模拟4.22】无界单词
- JZOJ 4466【GDOI2016模拟4.22】无界单词
- GDOI2016模拟4.22 无界单词 字符串上的动态规划
- 【GDOI模拟】无界单词
- GDOI2016赛前模拟4.23总结
- 【GDOI2016模拟4.23】飞机调度
- 【GDOI2016模拟4.23】数字方阵
- 【GDOI2016模拟4.23】轻重路径
- GDOI2016第一次模拟总结 4.21 ~ 4.23
- GDOI2016模拟8.10踢足球
- GDOI2016模拟8.8旋转
- GDOI2016模拟8.8处理器
- GDOI2016模拟8.13总结
- GDOI2016模拟8.14总结
- GDOI2016模拟8.14数树数
- GDOI2016模拟8.15总结
- GDOI2016模拟8.15蜘蛛侠
- MATLAB——scatter的简单应用
- poj2828 Buy Tickets(线段树,单点更新)
- java中四种操作(dom、sax、jdom、dom4j)xml方式详解与比较
- 【BZOJ4516】【Sdoi2016】生成魔咒 后缀数组 线段树
- CSS3动画工具
- 【GDOI2016模拟4.23】无界单词
- POJ 2739 Sum of Consecutive Prime Numbers(Two pointers)
- Java虚拟机如何加载Class文件
- span问题
- Linux杂项
- BZOJ1179: [Apio2009]Atm
- 给大家共享一个个人认为非常好的动画网站
- 公式加括号的所有可能
- ZOJ 3938-Defuse the Bomb【模拟,题看着挺长】(2016浙江省大学生程序设计竞赛)