sgu 232 Infinite Fraction
给出 \(n,k\) ,以及长度为 \(n\) 的原字符串 \(S[0,n-1]\) 。根据 \(S\) 构造出新的 \(n\) 个字符串 \(A[n]\) , \(A[i][j]=S[(i+jm)\%n]\) 。
求 \(A\) 中字典序最大的串,输出 \(A\) 的前 \(n\) 位 .
\(1\leq n\leq 150000,\ 0\leq k\leq 10^9\)
考虑 \(n,k\) 的最小公因数 \(d\) ,可也找到 \(d\) 个字符串,长度为 \(\frac{n}{d}\) .
把 \(d\) 个字符串每个复制一遍贴在后面构成一个长度为 \(\frac{2n}{d}\) 的字符串,需要找到,长度为 \(\frac{n}{d}\) 中字典序最大的字符串 .
因为本体内存只有 4mb,时限是 0.25s ,考虑哈希.
对于长度为 \(l\) 的任意两个串,都可以 \(O(l\log l)\) 地查询得到大小关系 . 二分相同前缀的长度哈希检查是否相等,然后比较后面一个字符即可 .
此时需要逆元数组,哈希数组,字符串保留存储数组三个. 长度皆为 \(n\) . 内存大概 1.7mb 左右,非常稳 .
时间复杂度 : \(O(n\log n)\)
空间复杂度 : \(O(n)\)
此题细节非常多,我 wa19 了很多次 .
code
//#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline") //Optimization flags
//#pragma GCC option("arch=native","tune=native","no-zero-upper") //Enable AVX
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2")
#include<bits/stdc++.h>
using namespace std;
char in[100005];
int iiter=0,llen=0;
inline char get(){
if(iiter==llen)llen=fread(in,1,100000,stdin),iiter=0;
if(llen==0)return EOF;
return in[iiter++];
}
inline int rd(){
char ch=get();while(ch<'0'||ch>'9')ch=get();
long long res=0;while(ch>='0'&&ch<='9')res=(res<<3)+(res<<1)+ch-'0',ch=get();
return res;
}
inline char get_char(){
char ch=get();while(ch<'0'||ch>'9')ch=get();return ch;
}
#define pb push_back
#define mp make_pair
#define fi first
#define se second
const int N=1e5+5e4+10;
int n,k,d;
char str[N];
inline int gcd(int a,int b){
return a%b==0?b:gcd(b,a%b);
}
const int p=998244353,mod=1e9+7;
inline int ksm(int x,int k){
if(k==0)return 1;
int res=ksm(x,k>>1);
res=1ll*res*res%mod;
if(k&1)res=1ll*res*x%mod;
return res;
}
int slen=0;
char s[N],ans[N];
int h[N],inv[N],P;
//l必然<slen
inline int get_hash(int l,int r){
return 1ll*(1ll*(r<slen?h[r]:1ll*(1ll*h[r%slen]*P%mod+h[slen-1])%mod)-(l?h[l-1]:0)+mod)%mod*inv[l]%mod;
}
inline bool cmp(int i,int j){
int low=1,high=slen+1;int res=0;
while(low<high){
int mid=(low+high)>>1;
if(get_hash(i,i+mid-1)==get_hash(j,j+mid-1)){
res=max(res,mid);
low=mid+1;
}else high=mid;
}
return res==slen?i<j:s[(i+res)%slen]>s[(j+res)%slen];
}
void work(int c){
h[0]=s[0];P=1;
for(int i=1;i<slen;i++){
P=1ll*P*p%mod;
h[i]=1ll*(1ll*s[i]*P%mod+h[i-1])%mod;
}
P=1ll*P*p%mod;
//处理出哈希值
int id=0;
for(int i=1;i<slen;i++)if(!cmp(id,i))id=i;
for(int i=id,j=c*slen;i<id+slen;i++,j++)ans[j]=s[i%slen];
}
void work_special(){
char mx='0';
for(int i=0;i<n;i++)mx=max(mx,str[i]);
for(int i=0;i<n;i++)putchar(mx);
}
bitset<N>ok;
int main(){
//预处理哈希表
inv[0]=1;inv[1]=ksm(p,mod-2);
for(int i=2;i<N;i++)inv[i]=1ll*inv[i-1]*inv[1]%mod;
n=rd();k=rd()%n;
for(int i=0;i<n;i++)str[i]=get_char();
if(k==0){ //判断k=0的特殊情况
work_special();
return 0;
}
d=gcd(n,k);
cerr<<d<<endl;
for(int c=0;c<d;c++){
slen=0;int pos=c;
for(int i=0;i<n/d;i++){
s[slen++]=str[pos];
pos=(pos+k)%n;
}
work(c);
}
//找到每一种循环的字符串,找出最小的
//字符串长度为 n/d,有d个这样的字符串
for(int i=0;i<n;i++)ok[i]=true;
for(int i=0;i<n/d;i++){
char mx='0';
for(int id=0,j=i;j<n;j+=n/d,id++)if(ok[id])mx=max(mx,ans[j]);
for(int id=0,j=i;j<n;j+=n/d,id++)if(ans[j]!=mx)ok[id]=false;
ans[i]=mx;
}
for(int i=0;i<d;i++)for(int j=0;j<n/d;j++)putchar(ans[j]);
return 0;
}
/*inline? ll or int? size? min max?*/

浙公网安备 33010602011771号