「JSOI2016」无界单词

题目描述

对于一个单词 $S$ ,如果存在一个长度 $l$,满足 $0\lt l\lt |S|$,并且使得 $S$ 长度为 $l$ 的前缀与 $S$ 长度为 $l$ 的后缀相同,JYY 则称 $S$ 是有界的。比如 `aabaa` 和 `ababab` 就都是有界的字符串。如果一个单词不存在这样的 $l$ ,则 JYY 称之为无界单词。

现在考虑所有仅由字母 `a` 和 `b` 组成的长度为 $N$ 的字符串,JYY想知道:
1. 一共有多少个无界单词?
2. 这些无界单词中,按字典序排列第 $K$ 小的单词是哪一个?

数据范围

对于全部数据,满足 $1\le T\le 5,1\le N\le 64$ ,并且保证对于任意测试数据,总存在第 $K$ 小的无界单词。

题解

考虑到每个有界单词总是能表示成两个无界单词放在首位且长度不超过该有界单词的一半。

于是可以考虑 $dp$ , $f_i$ 表示长度为 $i$ 的无界单词的个数,转移考虑容斥即可。

第二问只需要按位考虑即可,将 $dp$ 状态表示成长度为 $i$ ,且前 $len$ 为已经确定的无界单词的个数,转移是类似的。

代码

#include <bits/stdc++.h>
using namespace std;
#define U unsigned long long
const int N=70;
const U B=793999;
int T,n,a[N];
U k,f[N],b[N],g[N];
U H(int l,int r){
    return g[r]-g[l-1]*b[r-l+1];
}
bool J(int x){
    for (int i=1;i<x;i++)
        if (H(1,i)==H(x-i+1,x))
            return 0;
    return 1;
}
void work(){
    cin>>n>>k;
    f[1]=2;
    for (int i=2;i<=n;i++) f[i]=0;
    for (int i=2;i<=n;i++){
        for (int j=1;j+j<=i;j++)
            f[i]+=f[j]*((U)1<<(i-j-j));
        f[i]=((U)1<<i)-f[i];
    }
    if (n==64) f[n]--;
    cout<<f[n]<<endl;
    for (int h=1;h<=n;h++){
        g[h]=g[h-1]*B+1;a[h]=0;
        for (int i=1;i<=n;i++) f[i]=0;
        for (int i=1;i<=h;i++)
            if (J(i)) f[i]=1;
        for (int i=h+1;i<=n;i++){
            for (int j=1;j+j<=i;j++){
                if (i-j+1<=h){
                    if (H(1,h-i+j)==H(i-j+1,h))
                        f[i]+=f[j];
                }
                else f[i]+=f[j]*((U)1<<(i-j-max(j,h)));
            }
            f[i]=((U)1<<(i-h))-f[i];
        }
        if (f[n]<k) a[h]++,k-=f[n];
        putchar(a[h]+97);
        g[h]=g[h-1]*B+a[h]+1;
    }
    putchar(‘\n‘);
}
int main(){
    b[0]=1;
    for (int i=1;i<N;i++) b[i]=b[i-1]*B;
    for (scanf("%d",&T);T--;work());
    return 0;
}

原文地址:https://www.cnblogs.com/xjqxjq/p/11779182.html

时间: 2024-08-29 10:03:04

「JSOI2016」无界单词的相关文章

loj#2076. 「JSOI2016」炸弹攻击 模拟退火

目录 题目链接 题解 代码 题目链接 loj#2076. 「JSOI2016」炸弹攻击 题解 模拟退火 退火时,由于答案比较小,但是温度比较高 所以在算exp时最好把相差的点数乘以一个常数让选取更差的的概率降低 代码 #include<ctime> #include<cmath> #include<cstdio> #include<cstring> #include<algorithm> #define gc getchar() #define

稳定性「三十六计」- 无状态化

背景 随着容器化.云原生等的流行,DevOps团队也在不断鼓吹「以无状态为荣,以有状态为耻」.因为有状态的服务难以部署.难以扩展.下面我举几个自己工作中实际的例子. 实例1-依赖系统目录结构 刚转来基础架构的时候,接手了一个服务,原来是个应届生写的.所以可以理解,也就是基本能完成功能,反正也不是核心服务. 刚拿到的时候下载下来本地运行没成功,报错是说对某个目录下没有某个文件.读了一下代码发现是启动时需要加载一个本地认证的证书.从发布脚本目录下找到了那个证书文件,放到指定目录下后运行成功. 后来把

[JSOI2016]无界单词

题目 题意:求\(\rm border\)长度为\(0\)的\(n\)位\(0,1\)字符串个数,并求字典序第\(k\)小的那一个. 首先是计数,正向不是很好算,考虑正难则反:设\(f_i\)表示长度为\(i\)的\(\rm |border|=0\)的串的个数 一个串可能有多个\(\rm border\),我们考虑在其最小的\(\rm border\)长度\(j\)时计算它 则有\(f_i=2^i-\sum_{j=1}^{\lfloor \frac{i}{2}\rfloor}f_j2^{i-2\

loj2073 「JSOI2016」扭动的回文串

ref 主要是要理解"撑到"最长这个概念 (为啥我的代码这么长QAQ #include <iostream> #include <cstdio> using namespace std; typedef unsigned long long ull; int n, pa[200005], pb[200005], ans; ull bse1[200005], bse2[200005], hsa1[200005], hsa2[200005], hsb1[200005

#2071. 「JSOI2016」最佳团体

\(01\)分数规划不能直接套板子了,窝一开始想着用什么简单的方法缩点(每个点只有一个入度啊)然后跑拓扑图求解(保存每个点的最优值,通过牛顿迭代减少运算次数),问题是这样还要考虑人数,可不可做都不知道.转念一想,既然每个点只有一个入度,那么环从\(0\)号点\(jyy(orz)\)开始是肯定无法到达的(无法从任何一个点进入环).题目没说不可行就一定是可行的(雾),直接从\(0\)号点遍历即可,自然而然的拓扑图且还有个容易操作的性质,任意两条路不会汇合,理由如上,路只能分散,这不就是颗树吗?实现的

「JSOI2016」最佳团体

01分数规划 显然可以二分最大比值x,来验证是否可行 记当前比值为x,总战斗值为P与总招募费用为S 则 P - x*S >= 0 设 wi = pi - x*si 即 w1 + w2 + ... + wk >= 0 就转化为选k个节点,它们的w值非负,树上简单地dp一下就可求得 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N = 2505; 5 6 double l, r = 1e4, mid, f

LibreOJ #2012. 「SCOI2016」背单词

二次联通门 : LibreOJ #2012. 「SCOI2016」背单词 /* LibreOJ #2012. 「SCOI2016」背单词 Trie + 贪心 大家都吐槽题目反人类 可我觉得还好,毕竟见的多了 不会做啊.. 正解好巧妙 考虑一下,发现一操作完全不必要,可以省去 因为所有的字符串的后缀关系会形成一个树 那么把字符串倒序插入Trie中 建树,每次向子树小的一个点转移即可 */ #include <cstdio> #include <algorithm> #include

AC日记——「SCOI2016」背单词 LiBreOJ 2012

#2012. 「SCOI2016」背单词 思路: Orz: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 #define maxm 510005 int n,ch[maxm][26],tot=1,len,head[maxm],E[maxm],V[maxm],cnt=1; int val[maxm],cnt2,size[maxm],sta[maxm],top; long long ans,sum; ch

大数据和「数据挖掘」是何关系?---来自知乎

知乎用户,互联网 244 人赞同 在我读数据挖掘方向研究生的时候:如果要描述数据量非常大,我们用Massive Data(海量数据)如果要描述数据非常多样,我们用Heterogeneous Data(异构数据)如果要描述数据既多样,又量大,我们用Massive Heterogeneous Data(海量异构数据)--如果要申请基金忽悠一笔钱,我们用Big Data(大数据) 编辑于 2014-02-2817 条评论感谢 收藏没有帮助举报作者保留权利 刘知远,NLPer 4 人赞同 我觉得 大数据