【单调队列】【动态规划】[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;
}