【單調佇列】【動態規劃】[CQBZOJ3059]Bead
題目描述
Alex 喜歡玩網路遊戲,認為這是智力和體力的綜合鍛鍊。在一次遊戲活動中,
他意外獲得了一個傳說中威力極其強大的法寶:珠鏈。
珠鏈,顧名思義,就是由許多小珠子串起來的一條鏈。珠子有很多種顏色。
Alex 聽說過,只有將珠鏈打磨純淨,珠鏈才能發揮最大的威力。
純淨珠鏈是指這樣的珠鏈:它可以分成若干個長度相等的段,使任何兩段的
任何相同位置的珠子的顏色均不同,相同位置指珠子在段內的相對位置相同;而
且每段的長度以及劃分的段數也是有規範的,Alex 記得,每段包含的珠子數目
必須在L 到R 之間,而且劃分的段數不能少於S。
所謂打磨,就是從珠鏈的首和尾拿掉連續的若干個珠子。打磨後的純淨珠鏈
的威力等於它的每個珠子具有的魔力值之和。一個珠子的魔力值只與它在打磨前
的珠鏈中的位置有關。在查詢和分析了大量實驗資料以後,Alex 發現珠子的魔
力值等於珠子原來位置編號的約數個數!
興奮不已的Alex 想將珠鏈打磨成威力最大的純淨珠鏈。然而,馬上要參加
期末考試的Alex 來不及計算了,你能否幫助Alex 算出最大的威力值呢?
輸入
輸入檔名為bead.in。
第一行是四個整數N, L, R, S。
第二行是一個長度等於N 的字串,表示Alex 得到的珠鏈。字串的第i
個字元表示珠鏈的第i 個珠子的顏色。相同字母表示相同顏色。珠子的位置從1
編號到N。
輸出
輸出檔案為bead.out。
輸出一行,表示打磨後的純淨珠鏈的最大威力值。如果無法打磨成滿足要求
的純淨珠鏈,輸出-1.
樣例輸入
7 2 3 2
abcbcaa
樣例輸出
15
提示
能夠打磨出的合乎要求的純淨珠鏈有三種:bc/aa, abc/bca 和bcb/caa。其中威
力最大的是第三種,其威力值等於2+2+3+2+4+2 = 15。
如果給出的珠鏈是純淨珠鏈,那麼可以不打磨。純淨珠鏈必須能劃分成不少
於S 個等長的段且每段長度在L 到R 之間。
【資料規模和約定】
30% 的資料:1 ≤ N ≤ 100;
60% 的資料:1 ≤ N ≤ 100,000;
100% 的資料:1 ≤ N ≤ 500,000,1 ≤ L, R, S ≤ N, 0 ≤ R – L ≤ 10.
輸入的字串只包含大寫和小寫的英文字母。字母區分大小寫。
題目分析
首先我們列舉
注:
那麼總的演算法時間複雜度就是
程式碼
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 500000;
int vis[60][500010], ans=-1, s[MAXN+10], sum[MAXN+10], n, L, R, S;
void solve(int l){
int Max = 0;
for(int i=1;i<=n;i++){
Max = max(Max, vis[s[i]][i%l]);
int Lent = i-Max;
if(Lent/l >= S){
Lent -= Lent % l;
ans = max(ans, sum[i]-sum[i-Lent]);
}
vis[s[i]][i%l] = i;
}
memset(vis, 0, sizeof vis);
}
char str[MAXN+10];
int main(){
scanf("%d%d%d%d%s", &n, &L, &R, &S, str+1);
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j+=i) sum[j] ++;
sum[i] += sum[i-1];
}
for(int i=1;i<=n;i++){
if(str[i] >= 'a' && str[i] <= 'z') s[i] = str[i] - 'a';
else s[i] = str[i] - 'A' + 26;
}
for(int i=L; i<=R; i++) solve(i);
printf("%d\n", ans);
return 0;
}