2019 CCPC秦皇岛 J 题 MUV LUV EXTRAKMP 求最小循环节

Posted lasomisolaso~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019 CCPC秦皇岛 J 题 MUV LUV EXTRAKMP 求最小循环节相关的知识,希望对你有一定的参考价值。

题意:

原题意是给出一个有理数的前一部分,求这个有理数的无限循环部分是什么。有一个值来评估猜的准确度。转换一下就成了下面的题意:
给出一个字符串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;

以上是关于2019 CCPC秦皇岛 J 题 MUV LUV EXTRAKMP 求最小循环节的主要内容,如果未能解决你的问题,请参考以下文章

Problem A. MUV LUV EXTRA(kmp求最小循环节)

2019 China Collegiate K. MUV LUV UNLIMITED(思维,博弈)

2019-ccpc秦皇岛现场赛

Codeforces Gym 102361A Angle Beats CCPC2019秦皇岛A题 题解

[CCPC] 2017秦皇岛H Prime Set | 二分图最大匹配 [据说是个金牌题]

2019CCPC秦皇岛 I Invoker