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?*/
posted @ 2022-02-05 11:32  xyangh  阅读(12)  评论(0)    收藏  举报