【2019 CCPC 秦皇岛】J - MUV LUV EXTRA

时间:2019-10-15
本文章向大家介绍【2019 CCPC 秦皇岛】J - MUV LUV EXTRA,主要包括【2019 CCPC 秦皇岛】J - MUV LUV EXTRA使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

原题:

题意:

给你两个整数a和b,再给你一个正小数,整数部分忽略不计,只考虑小数部分的循环节,对于所有可能的循环节,令其长度为l,在小数部分循环出现的长度为p,最后一个循环节允许不完整,但是缺少的部分不计入循环长度

问你a*p-b*l的最小值是多少

考虑的循环节必须至少在小数部分中出现一次,小数部分的前缀可以不属于循环部分

这题也是一眼很棘手,和后缀数组和后缀自动机似乎都有相似之处

但是实际做法是kmp

翻转原串是关键思路,这样保证了能把原串前缀的不是循环部分的部分忽略掉,从而方便地利用next数组的性质

把小数部分串反过来,那么这个串的前缀就一定是循环部分

因为最后循环节允许不完整,所以考虑把一个循环节分成AB两部分,其中B是最后一个循环节缺的部分

考虑next数组的性质:next[i]表示子串[1,i]最长的前后缀长度,使得此长度的前后缀相等

那么对于ACA形式的串,其中A指最长的相同前后缀,把C接到A后边就可以变成ACA(C)的循环形式,前后缀有相交情况时同理

对于循环部分[1,i],出现长度就是i,出现长度固定,只需求出此时长度最小的循环节

由next的性质,保证[1,i-next[i]]是最小的循环节

可以反证,考虑ABABABABA,如果它被i-nxt[i]和next[i]+1划分为ABA BAB ABA,即认为[1,6]和[4,9]是相同的前后缀,且有多余的循环节被统计到了[1,i-nxt[i]]和[nxt[i]+1,i]里

那么此时可以从[1,i-nxt[i]]和[nxt[i],i]中各拿出一个循环节放到中间,易证此时仍然符合next[i]的性质,即之前求出的next[i]是错误的

所以得证,[1,i-next[i]]一定是最小的循环节

那么把小数部分倒过来,从左到右扫一遍,每次根据next[i]计算,然后统计到答案即可

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std;
 7 #define LL long long
 8 LL a,b;
 9 char s[11000000];
10 int c[11000000],n=0;
11 int nxt[11000000];
12 LL ans;
13 void gtnxt(){
14     int tmp=0;
15     nxt[1]=0;
16     for(int i=2;i<=n;++i){
17         while(tmp&&c[tmp+1]!=c[i])  tmp=nxt[tmp];
18         if(c[tmp+1]==c[i])  ++tmp;
19         nxt[i]=tmp;
20         /*if(nxt[i]){
21             if(nxt[i]>=i-nxt[i]+1)  ans=max(ans,a*i-b*(i-nxt[i]));
22             if(nxt[i]==i-nxt[i])  ans=max(ans,a*i-b*nxt[i]);
23             ans=max(ans,a*i*/
24         if(nxt[i])  ans=max(ans,a*i-b*(i-nxt[i]));
25     }
26 }
27 int main(){
28     //freopen("ddd.in","r",stdin);
29     while(scanf("%lld%lld",&a,&b)!=EOF){
30         ans=-1e18,n=0;
31         scanf("%s",s);
32         for(int i=strlen(s)-1;i>=0;--i){
33             if(s[i]=='.')  break;
34             c[++n]=s[i]-'0';
35         }
36         if(a-b>0)  ans=(a-b)*n;
37         else  ans=a-b;
38         gtnxt();
39         cout<<ans<<endl;
40         /*for(int i=1;i<=n;++i)  cout<<c[i]<<" ";
41         cout<<endl;
42         for(int i=1;i<=n;++i)  cout<<nxt[i]<<" ";
43         cout<<endl;*/
44     }
45     return 0;
46 }
View Code

原文地址:https://www.cnblogs.com/cdcq/p/11678950.html