BZOJ4532: [BeiJing2014 WinterCamp] 珠链

Description

Alex喜欢玩网络游戏,认为这是智力和体力的综合锻炼。在一次游戏活动中,他意外获得了一个传说中威力极其强大的法宝:珠链。

珠链,顾名思义,就是由许多小珠子串起来的一条链。珠子有很多种颜色。Alex听说过,只有将珠链打磨纯净,珠链才能发挥最大的威力。

纯净珠链是指这样的珠链:它可以分成若干个长度相等的段,使任何两段的任何相同位置的珠子的颜色均不同,相同位置指珠子在段内的相对位置相同;而且每段的长度以及划分的段数也是有规范的,Alex记得,每段包含的珠子数目必须在L到R之间,而且划分的段数不能少于S。

所谓打磨,就是从珠链的首和尾拿掉连续的若干个珠子。打磨后的纯净珠链的威力等于它的每个珠子具有的魔力值之和。一个珠子的魔力值只与它在打磨前的珠链中的位置有关。在查找和分析了大量实验数据以后,Alex发现珠子的魔力值等于珠子原来位置编号的约数个数!

兴奋不已的Alex想将珠链打磨成威力最大的纯净珠链。然而,马上要参加期末考试的Alex来不及计算了,你能否帮助Alex算出最大的威力值呢?

Input

第一行是四个整数N, L, R, S。

第二行是一个长度等于N的字符串,表示Alex得到的珠链。字符串的第i个字符表示珠链的第i个珠子的颜色。相同字母表示相同颜色。珠子的位置从1编号到N。

1 ≤ N ≤ 500,000,1 ≤ L, R, S ≤ N, 0 ≤ R – L ≤ 10. 输入的字符串只包含大写和小写的英文字母。字母区分大小写。

Output

输出一行,表示打磨后的纯净珠链的最大威力值。如果无法打磨成满足要求的纯净珠链,输出 -1.

Sample Input

7 2 3 2
abcbcaa

Sample Output

15
【样例解释】
能够打磨出的合乎要求的纯净珠链有三种:bc/aa, abc/bca和bcb/caa。其中威力最大的是第三种,其威力值等于2+2+3+2+4+2 = 15。
如果给出的珠链是纯净珠链,那么可以不打磨。纯净珠链必须能划分成不少于S个等长的段且每段长度在L到R之间。

因为R-L+1<=10,所以我们可以枚举每一段的长度。

对于“任何两段的任何相同位置的珠子的颜色均不同”,我们按模x分类,计算出每个位置上一个和它颜色相同的位置,那么一段珠子能包含的最左端点就是一个区间的最大值。

然后滑动一下窗口即可。

#include<cstdio>
#include<cctype>
#include<queue>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i;i=next[i])
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c==‘-‘) f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-‘0‘;
    return x*f;
}
typedef long long ll;
const int maxn=500010;
int n,s,S[maxn],Q[maxn],ans=-1;
int f[maxn],g[maxn],A[maxn],last[55];
char str[maxn];
int idx(char c) {return (c>=‘a‘&&c<=‘z‘)?c-‘a‘:c-‘A‘+26;}
ll solve(int x) {
	rep(i,0,x-1) {
		for(int j=i;j<n;j+=x) f[j]=last[A[j]],last[A[j]]=j;
		for(int j=i;j<n;j+=x) last[A[j]]=-1;
	}
	int l=1,r=0;
	rep(i,0,n-1) {
		while(l<=r&&f[Q[r]]<f[i]) r--;Q[++r]=i;
		while(Q[l]<=i-x) l++;
		if(i>=x-1) g[i-x+1]=f[Q[l]];
	}
	rep(i,0,x-1) {
		l=i;
		for(int j=i;j+x-1<n;j+=x) {
			while(l<=g[j]) l+=x;
			if(j-l>=(s-1)*x) ans=max(ans,S[j+x]-S[l]);
		}
	}
}
int main() {
	int l,r;
	memset(last,-1,sizeof(last));
	n=read();l=read();r=read();s=read();
	rep(i,1,n) for(int j=i;j<=n;j+=i) S[j]++;
	rep(i,2,n) S[i]+=S[i-1];
	scanf("%s",str);
	rep(i,0,n-1) A[i]=idx(str[i]);
	rep(i,l,r) solve(i);
	printf("%d\n",ans);
	return 0;
}

  

时间: 2024-12-11 15:26:10

BZOJ4532: [BeiJing2014 WinterCamp] 珠链的相关文章

[BZOJ4533][BeiJing2014 WinterCamp] 数据

试题描述 为了写论文,Alex经常要整理大量的数据. 这一次,Alex面临一个严峻的考验:他需要实现一个数据结构来维护一个点集. 现在,二维平面上有N个点.Alex 需要实现以下三种操作: 1. 在点集里添加一个点: 2. 给出一个点,查询它到点集里所有点的曼哈顿距离的最小值: 3. 给出一个点,查询它到点集里所有点的曼哈顿距离的最大值. 两个点的曼哈顿距离定义为它们的横坐标差的绝对值与纵坐标差的绝对值的和.这么困难的问题,Alex当然不会做,只好再次请你帮忙了. 输入 第一行包含一个整数N,表

HDU 5730 - Shell Necklace

题意: 给出连续的1-n个珠子的涂色方法 a[i](1<=i<=n), 问长度为n的珠链共有多少种涂色方案 分析: 可以得到DP方程: DP[n] = ∑(i=1,n) (DP[n-i]*a[i]). 该方程为卷积形式,故 CDQ + FFT CDQ: 将 [l,r] 二分, 先得到[l,mid]的答案,再更新[l,mid]对[mid+1,r]的贡献.   对任意 DP[j](mid+1 <= j <= r), [l,mid] 对其贡献为 ∑(i=l,mid) (DP[i]*a[j

精选文章推荐汇总-2018.03.01

大话爬虫的实践技巧 作者:SFLYQ简介:如今已然是大数据时代,数据正在驱动着业务开发,驱动着运营手段,有了数据的支撑可以对用户进行用户画像,个性化定制,数据可以指明方案设计和决策优化方向,所以互联网产品的开发都是离不开对数据的收集和分析,数据收集的一种是方式是通过上报API进行自身平台用户交互情况的捕获,还有一种手段是通过开发爬虫程序,爬取竞品平台的数据,后面就重点说下爬虫的应用场景和实践中会遇到的问题和反反爬虫的一些套路与技巧. 爱情有备胎,数据中心有MC-LAG 作者:姜汁啤酒简介:最近咱

使用Marbles弹珠游戏模拟区块链资产转移

本实践基于华为云区块链服务,以基于区块链的弹珠资产转移Marbles Demo部署为例进行演示,旨在帮助您了解链代码的基础知识以及如何使用Fabric网络开发应用程序,帮助您快速上手使用. 关于Demo这是一个简单的资产转移演示,多个用户之间可以创建并相互转移弹珠资产,同时您还能看到详细的交易信息及区块链信息.界面如下: ×××如果您需要查看Demo应用的源码,请点击下载源码进行下载查看,希望对您的应用开发有所帮助. 准备工作华为云区块链服务是基于容器所构建的集群进行部署的,同时为使外网能够正常

HDU 3980 (SG 环变成链 之前的先手变成后手)

题意 两个人在一个由 n 个玻璃珠组成的一个圆环上玩涂色游戏,游戏的规则是: 1.每人一轮,每轮选择一个长度为 m 的连续的.没有涂过色的玻璃珠串涂色 2.不能涂色的那个人输掉游戏 Aekdycoin 先手 开始时候是一个环,第一个人涂色后就变成了链,这时候就可以使用尼姆博弈了.但是注意一点此时第二个人应该变成尼姆博弈中的先手了. 第一次涂色后 变成 abcdxyzk 先手 n < m 先手无法涂 后手胜 Sample Input2 3 1 // n m4 2 Sample OutputCase

数据结构第四篇——线性表的链式存储之双向链表

?注:未经博主同意,不得转载. 前面讨论的单链表,每个结点中只有一个指针域,用来存放指向后继结点的指针,因此,从某个结点出发只能顺时针往后查找其他结点.若要查找某个结点的直接前驱,则需要从头指针开始沿链表探寻,处理起来十分不方便.为克服单链表的这一缺点,可引入双向链表. 双向链表中每一个结点含有两个指针域,一个指针指向其直接前驱结点,另一个指针指向直接后继结点.和单链表类似,双向链表一般也只有头指针唯一确定:同样也可设头结点,使得双向链表的某些操作简便一些. 双向链表结构定义如下:  双向链表是

luoguP2590 [ZJOI2008]树的统计 [树链剖分] [TLE的LCT]

题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身 输入输出格式 输入格式: 输入文件的第一行为一个整数n,表示节点的个数. 接下来n – 1行,每行2个整数a和b,表示节点a和节点b之

链栈的实现

链栈即链式栈,也就是说我们不用再考虑空间的大小,可随心所欲的进行数据的插入/删除了.和顺序栈一样,仍然要保持其stack的特性,只在一端进行插入和删除,后进先出. 示例代码: #ifndef _LINKSTACK_H #define _LINKSTACK_H typedef int ElemType; typedef int Status; typedef struct linkStack { ElemType data; struct linkStack * top; }linkStack;

链队列代码及应用

链队列代码 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <time.h> #define OK 1 #define ERROR 0 #define OVERFLOW -2 #define TRUE 1 #define FALSE 0 typedef int Status; typedef int ElemType; typedef struct Qnode{ int