bzoj4974: [Lydsy八月月赛]字符串大师

传送门

题目可转换为已知一个串kmp之后的nxt数组,求字典序最小的原串。

已知第i位结尾的串循环节长度位x,那么nxt[i]=i-x;

当nxt不为0时,s[i]=s[nxt[i]];

nxt为0时,那么考虑kmp的过程,沿着nxt[i-1]一直往前跑找到的每一个j,s[j+1]都不能是现在的s[i],那么在一路求nxt的过程中就从前往后递推用一个二进制串表示一路的nxt的后一位出现过的字母,然后每次取未出现过的字典序最小的字母即可;

//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<ctime>
const int N=100007;
typedef long long LL;
using namespace std;
int n,nxt[N],vis[N];
char s[N];

template<typename T> void read(T &x) {
    T f=1; x=0; char ch=getchar();
    while(ch!=‘-‘&&(ch<‘0‘||ch>‘9‘)) ch=getchar();
    if(ch==‘-‘) f=-1,ch=getchar();
    for(;ch>=‘0‘&&ch<=‘9‘;ch=getchar()) x=x*10+ch-‘0‘; x*=f;
}

int main() {
#ifdef DEBUG
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
#endif
    read(n);
    for(int i=1;i<=n;i++) {
        read(nxt[i]);
        nxt[i]=i-nxt[i];
    }
    s[0]=‘a‘; vis[1]=1;
    for(int i=2;i<=n;i++) {
        if(nxt[i]!=0) s[i-1]=s[nxt[i]-1];
        else {
            for(int j=0;j<26;j++)
                if(!(vis[i-1]&(1<<j))) {
                    s[i-1]=‘a‘+j;
                    break;
                }
        }
        vis[i]=(vis[nxt[i]]|(1<<(s[nxt[i]]-‘a‘)));
    }
    puts(s);
    return 0;
}

原文地址:https://www.cnblogs.com/Achenchen/p/8185648.html

时间: 2024-11-05 19:45:07

bzoj4974: [Lydsy八月月赛]字符串大师的相关文章

【bzoj4974】字符串大师 逆模拟KMP

题目描述 一个串T是S的循环节,当且仅当存在正整数k,使得S是$T^k$(即T重复k次)的前缀,比如abcd是abcdabcdab的循环节.给定一个长度为n的仅由小写字符构成的字符串S,请对于每个k(1<=k<=n),求出S长度为k的前缀的最短循环节的长度$per_i$.字符串大师小Q觉得这个问题过于简单,于是花了一分钟将其AC了,他想检验你是否也是字符串大师. 小Q告诉你n以及$per_1,per_2,...,per_n$,请找到一个长度为n的小写字符串S,使得S能对应上per. 输入 第一

【BZOJ4953】lydsy七月月赛 F DP

[BZOJ4953]lydsy七月月赛 F 题面 题解:设f[i][j]表示第i个强度取为j时的最小误差.那么每次转移时,我们只计算j'和j之间的像素点带来的误差,于是有: $f[i][j]=min(f[i-1][k]+g(k..mid,k)+g(mid+1...j,j))|mid={k+j\over 2}$ 其中,&g(a,b)=P_a*(a-b)^2\\=P_a*a*a-2*P_a*a*b+2*P_a*b*b& 于是维护P_a*a*a,P_a*a,P_a的前缀和即可. #include

【BZOJ4950】lydsy七月月赛 C 二分图最大匹配

[BZOJ4950]lydsy七月月赛 C 题面 题解:比较直接的想法就是:每行,每列的最大值都留下,剩下的格子都变成1.但是如果一个格子既是行的最大值又是列的最大值,那么我们只需要把它留下即可.这就变成了一个二分图最大匹配问题,乱搞即可. #include <cstdio> #include <cstring> #include <iostream> using namespace std; typedef long long ll; int n,m,cnt,now;

【BZOJ4952】lydsy七月月赛 E 二分答案

[BZOJ4952]lydsy七月月赛 E 题面 题解:傻题...二分答案即可,精度有坑. #include <cstdio> #include <cstring> #include <iostream> using namespace std; double eps=1e-9; int n,t; int d[1010],s[1010]; bool solve(double x) { double ret=0; for(int i=1;i<=n;i++) ret+

BZOJ 4974: 字符串大师

一个串T是S的循环节,当且仅当存在正整数k,使得S是T^k(即T重复k次)的前缀,比如abcd是abcdabcdab的循环节 .给定一个长度为n的仅由小写字符构成的字符串S,请对于每个k(1<=k<=n),求出S长度为k的前缀的最短循环节的 长度per_i.字符串大师小Q觉得这个问题过于简单,于是花了一分钟将其AC了,他想检验你是否也是字符串大师. 小Q告诉你n以及per_1,per_2,...,per_n,请找到一个长度为n的小写字符串S,使得S能对应上per. Input 第一行包含一个正

【BZOJ4919】[Lydsy六月月赛]大根堆 线段树合并

[BZOJ4919][Lydsy六月月赛]大根堆 Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切地说,你需要选择尽可能多的节点,满足大根堆的性质:对于任意两个点i,j,如果i在树上是j的祖先,那么v_i>v_j. 请计算可选的最多的点数,注意这些点不必形成这棵树的一个连通子树. Input 第一行包含一个正整数n(1<=n<=200000),表示节点的个数. 接下来n行,每行两个整数v

[BZOJ4920][Lydsy六月月赛]薄饼切割

[BZOJ4920][Lydsy六月月赛]薄饼切割 试题描述 有一天,tangjz 送给了 quailty 一张薄饼,tangjz 将它放在了水平桌面上,从上面看下去,薄饼形成了一个 \(H \times W\) 的长方形. tangjz 交给了 quailty 一根木棍,要求 quailty 将木棍轻轻放到桌面上.然后 tangjz 会以薄饼中心作为原点,将木棍绕着原点旋转一圈,将木棍扫过的部分切下来送给 quailty. quailty 已经放好了木棍,请写一个程序帮助他们计算 quailt

bzoj 4921: [Lydsy六月月赛]互质序列

4921: [Lydsy六月月赛]互质序列 Time Limit: 1 Sec  Memory Limit: 256 MBSubmit: 188  Solved: 110[Submit][Status][Discuss] Description 你知道什么是"互质序列"吗?那就是所有数的最大公约数恰好为1的序列. "互质序列"非常容易找到,但是我们可以尝试通过删除这个序列的一个非空连续子序列来扩大它的最大公约数. 现在给定一个长度为n的序列,你需要从中删除一个非空连

字符串大师

Description 一个串T是S的循环节,当且仅当存在正整数k,使得S是T^k(即T重复k次)的前缀,比如abcd是abcdabcdab的循环节.给定一个长度为n的仅由小写字符构成的字符串S,请对于每个k(1<=k<=n),求出S长度为k的前缀的最短循环节的长度per_i.字符串大师小Q觉得这个问题过于简单,于是花了一分钟将其AC了,他想检验你是否也是字符串大师.小Q告诉你n以及per_1,per_2,...,per_n,请找到一个长度为n的小写字符串S,使得S能对应上per. Input