P2240 【深基12.例1】部分揹包問題
阿新 • • 發佈:2022-03-08
P3538 [POI2012]OKR-A Horrible Poem
Describe:
第一行一個正整數 \(n(n \le 500 000)\),表示 \(S\) 的長度。
第二行n個小寫英文字母,表示字串 \(S\)。
第三行一個正整數 \(q(q \le 2 000 000)\),表示詢問次數。
下面q行每行兩個正整數\(a,b(1\le a\le b\le n)\),表示詢問字串 \(S[a…b]\) 的最短迴圈節長度。
Sol:
顯然的,最短迴圈長度的 \(k\ (k\in Z)\) 倍一定是 \(b-a+1\),也就是說迴圈長度 \(len\) 一定是長度的因子。
再就因為是迴圈的,所以從 \(l \to l+len-1 \ \text{和} r-len+1 \to r\)
那麼我們就可以用雜湊做到 \(\mathcal{O(1)}\)
注意的是,列舉因子要從大到小列舉,另外,我們可以利用線性篩是利用列舉最小質因子的方式來記錄下每個數的最小質因子,然後除一下找到最大因子,以此類推。
Code:
/* Knowledge : Rubbish Algorithm Work by :Gym_nastics Time : O(AC) */ #include<cmath> #include<queue> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int INF=0x3f3f3f3f; const int Mod=1e9+7; const int Base=131; const int N=1e6+6; int read() { int x=0,f=0;char ch=getchar(); for(;!isdigit(ch);ch=getchar()) f|=(ch=='-'); for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch&15); return f?-x:x; } void print(int x) { if(x<0) putchar('-'),x=-x; if(x>9) print(x/10); putchar(x%10+48); } int Prime[N],M[N],cnt,h[N],P[N];bool vis[N]; void prepare(){ for(int i=2;i<=1e6;i++){ if(!vis[i]) Prime[++cnt]=i,M[i]=i; for(int j=1;j<=cnt&&i*Prime[j]<=1e6;j++){ vis[i*Prime[j]]=1;M[i*Prime[j]]=Prime[j]; if(!(i%Prime[j])) break; } } } char ch[N]; signed main() { int l=read();cin>>ch+1;int Q=read();P[0]=1;prepare(); for(int i=1;i<=l;i++) h[i]=h[i-1]*Base+ch[i],P[i]=P[i-1]*Base; while(Q--){ int l=read(),r=read(),len,ans; ans=len=r-l+1;while(len^1){ int k=ans/M[len];len/=M[len]; if(!(h[r-k]-h[l-1]*P[r-k-l+1]^h[r]-h[l-1+k]*P[r-k-l+1])) ans=k; }print(ans);putchar('\n'); } return 0; }