MUV LUV EXTRA(循环节)

测试地址
Problem Description

鉴纯夏是一名成绩不太好的高中生。一天她在数学考试中碰到了一道求某条线段长度的问题。因为她并不会做这道题,所以她准确地作图后用尺子量出了这条线段的长度。不幸的是,答案在10进制下为一个无限小数,纯夏只量出了这个无限小数在10进制表示下的前若干位。纯夏猜测问题的答案为一个有理数,所以答案为一个无限循环小数,

如13=0.333⋯,3635=1.0285714285714⋯。

纯夏希望从这个无限小数的前n位猜出原本的数字。纯夏意识到,猜测的循环节太长或循环节已经开始出现的部分长度太短是不可信的。
举个例子,若她量出的小数为1.0285714285714,显然假设循环节为0285714285714(长度为13)或假设循环节为428571(已经开始出现的部分长度为7)都不如假设循环节为285714(长度为6,已经开始出现的部分长度为12)可靠。

因此她定义一个循环节的可靠程度为a×循环节已经开始出现的部分长度−b×循环节长度。请你帮她求出最可靠的循环节的可靠程度为多少。

解题思路
在用kmp中nex数组求字符串循环节时,n-nex[n]一定是最短循环节长度,就算缺若干字符,该结论仍成立。

代码示例

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1e7+10;
char str[N],s[N];
typedef long long ll;
ll a,b,ans = 0;
int nex[N],tot ;
void getNex(char * s){
	int len = strlen(s)-1; nex[1] = 0;
	for(int i = 2,j = 0;i <= len;i++){
		while(j > 0 && s[i] != s[j+1]) j = nex[j];
		if(s[i] == s[j+1]) j++;
		nex[i] = j;
	}
}
void solve(){
	getNex(s); ans = a-b;
	for(int i = 2;i <= tot;i++){
		int x = i - nex[i] , y = i;
		ans = max(ans,a*y - b*x);
	}
	printf("%lld\n",ans);
}
int main(){
	//freopen("123.txt","r",stdin);
	//freopen("222.txt","w",stdout);
	while(~scanf("%lld%lld",&a,&b)){
		scanf("%s",str); tot = 0;
		/* 去掉整数部分,方便处理 */
		for(int i = strlen(str)-1;i >= 0;i--) 
			if(str[i] == '.') break;
			else s[++tot] = str[i];
		s[0] = '#'; s[tot+1] = '\0';
		solve();
	}
	return 0;
}
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 程序猿惹谁了 设计师:白松林 返回首页