【题解】 NC5157B 密码系统
密码系统
https://ac.nowcoder.com/acm/contest/5157/B
solution
其实本题只要解决一个问题,剩下的就是模拟了。
这个问题就是如何快速的比较两个字符串的字典序。这是一个非常经典的思路。我们对这两个字符串都哈希一遍,然后二分一下这两个字符串最长的公共前缀长度。然后比较最长公共前缀的下一位上的字符就行了。因为所有要比较的字符串都在同一个母串上。我们只要对这个母串进行一遍哈希就行了。
剩下的按照题目中讲的模拟即可。
code
/*
* @Author: wxyww
* @Date: 2020-04-17 19:15:03
* @Last Modified time: 2020-04-17 19:23:46
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<ctime>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 1000010;
ll read() {
ll x = 0,f = 1;char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1; c = getchar();
}
while(c >= '0' && c <= '9') {
x = x * 10 + c - '0'; c = getchar();
}
return x * f;
}
char s[N];
ull hs[N],base[N],B = 28;
int n,K,now[N];
ull get(int l,int r) {
return hs[r] - hs[l - 1] * base[r - l + 1];
}
int check(int x,int y) {
int l = 1,r = K,ans = 0;
while(l <= r) {
int mid = (l + r) >> 1;
if(get(x,x + mid - 1) == get(y,y + mid - 1)) ans = mid,l = mid + 1;
else r = mid - 1;
}
return s[x + ans] < s[y + ans];
}
int main() {
n = read(),K = read();
scanf("%s",s + 1);
for(int i = n + 1;i <= n + n;++i)
s[i] = s[i - n];
base[0] = 1;
for(int i = 1;i <= n + n;++i) {
hs[i] = hs[i - 1] * B + s[i] - 'a' + 1;
base[i] = base[i - 1] * B;
}
for(int i = 1;i <= n;++i) {
if(!now[i % K]) now[i % K] = i;
else {
if(check(now[i % K],i)) now[i % K] = i;
}
}
int ans = now[0];
for(int i = 1;i < K;++i) {
if(check(now[i],ans)) ans = now[i];
}
for(int i = ans;i <= ans + K - 1;++i)
putchar(s[i]);
return 0;
}
查看2道真题和解析
