(imodk)modn=(jmodk)modn⟹i−j=p∗k+q∗n=t∗gcd(n,k)
所以问题转变为:有
gcd(n,k)
个本质不同的字符串,每个字符串长度都为
n/gcd(n,k)
, 求它们中字典序最大的字符串。
最大表示法。 时间复杂度 O(n)
注意输出时要补成 n <script type="math/tex" id="MathJax-Element-773">n</script> 位。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
const int maxn = 150005;
int n, k, len;
char d[maxn];
bool hash[maxn];
char s[maxn<<1];int sl;
char ans[maxn];int at;
int gcd(int a,int b)
{
return (!b)?a:gcd(b,a%b);
}
int getmax()
{
for(int i = 0; i < sl; i++)
s[i+sl] = s[i];
int i = 0, j = 1, k = 0;
while(i < sl && j < sl)
{
if(k == sl) break;
if(s[i+k] > s[j+k])
j += k+1, k = 0;
else if(s[i+k] < s[j+k])
i += k+1, k = 0;
else
k++;
if(i == j) j++;
}
return i;
}
bool compare(int t, int x)
{
for(int i = 0; i < len; i++)
{
if(d[t] > d[x])
return true;
else if(d[t] < d[x])
return false;
else
{
t = (t+k)%n;
x = (x+k)%n;
}
}
return false;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("sgu232.in","r",stdin);
freopen("sgu232.out","w",stdout);
#endif
std::cin >> n >> k;
scanf("%s", d);
len = n/gcd(n,k);
for(int i = 0; i < n; i++)
if(!hash[i])
{
int t = i; sl = 0;
while(!hash[t])
{
hash[t] = true;
s[sl++] = d[t];
t = (t+k)%n;
}
int st = ((long long)k*getmax() + i)%n;
if(compare(st, at)) at = st;
}
for(int i = 0; i < n; i++)
ans[i] = d[at], at = (at+k)%n;
printf("%s", ans);
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
#endif
return 0;
}