2019 CCPC秦皇岛 J 题 MUV LUV EXTRA【KMP 求最小循环节】

题意:

原题意是给出一个有理数的前一部分,求这个有理数的无限循环部分是什么。有一个值来评估猜的准确度。转换一下就成了下面的题意:
给出一个字符串s,有某一个子串,设p为该子串在s的某个后缀中的匹配长度,l为该子串的长度。这个子串的值就是a * p - b * l。求所有的在s的某个后缀中至少循环一次的子串中值最大的是多少。

思路:

观察给出的计算子串值的式子,我们要让匹配长度尽量长,子串尽量短才能让这个值尽量大。
我们发现如果固定了子串匹配的后缀,那么这个最大的值的子串就确定了,它就是这个后缀的最小循环节。
那么做法就很明显了,我们枚举每一个后缀,求出它们的最小循环节,计算值来更新答案就行了。
后缀的最小循环节不太好操作,可以提前把 s s s反转。

代码:

用KMP来求最小循环节。
不论是不是完整的循环串,字符串s的长度为len,则s的最小循环节长度为len-next[len]。注意用的是字符串长度的next[len].

/*
 * @file J.cpp
 * @path D:\code\ACM\gym\CCPC_Qinhuangdao\J.cpp
 * @author Xiuchen
 * @date  2020-10-21 20:54:11
*/

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<cmath>
#include<math.h>
#include<iostream>
#include<algorithm>
#include<unordered_map>
//#define DEBUG
#define M_PI 3.14159265358979323846
#define dbg(x) cout << #x << " = "<< (x) << endl
#define dbg2(x1,x2) cout << #x1 << " = " << x1 << " " << #x2 << " = " << x2 << endl
#define dbg3(x1,x2,x3) cout<< #x1 << " = " << x1 << " " << #x2 << " = " << x2 << " " << #x3 << " = " << x3 <<endl
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fLL;
const int maxn = 1e7 + 100;
int gcd(int a, int b){
    return b ? gcd(b, a % b) : a;
}
ll a, b;
int n = 0, nxt[maxn];
char t[maxn], s[maxn], ss[maxn];
void kmp_pre(){
    int i, j;
    j = nxt[0] = -1;
    i = 0;
    while(i < n){
        while(-1 != j && s[i] != s[j]) j = nxt[j];
        nxt[++i] = ++j;
    }
}
int main(){
#ifdef DEBUG
    freopen("input.txt", "r", stdin);
//	freopen("output.txt", "w", stdout);
#endif
    scanf("%lld%lld", &a, &b);
    scanf("%s", t + 1);
    int lent = strlen(t + 1);
    bool flag = false;
    for(int i = 1; i <= lent; i++){
        if(flag) ss[++n] = t[i];
        if(t[i] == '.') flag = true;
    }
    for(int i = 1; i <= n; i++) s[i - 1] = ss[n - i + 1];
    s[n] = '\0';
    kmp_pre();
    ll ans = a - b;
    for(int i = 1; i <= n; i++) ans = max(ans, a * i - b * (i - nxt[i]));
    printf("%lld\n", ans);
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值