题意:
给一个无线循环小数的前几位,给n,m
选择其中一种出现在前几位的循环节方式(a个数),循环节的长度b
使得n*a-m*b最大
样例:
2 1
12.1212
输出 6
选择2,2*1-1*1=1;
选择12,2*4-2*1=6;
选择21,2*3-2*1=4;
选择212,2*3-3*1=3;
选择1212,2*4-4*1=4;
思路:
将小数部分,倒过来,求每个点的最小循环节,kmp中i-next[i]代表最小循环节
当倒过来的小数部分,n*i-m*(i-next[i])中的最大就是答案
#include<bits/stdc++.h> using namespace std; #define ll long long #define il inline #define it register int #define inf 0x3f3f3f3f #define lowbit(x) (x)&(-x) #define mem(a,b) memset(a,b,sizeof(a)) #define mod 998244353 const int maxn=1e7+10; ll n,m; int nexts[maxn]; char s[maxn],s2[maxn]; int p2=0; il void GetNext(int l){ int i=0; int j=-1; nexts[0]=-1; while(i<l){ if(j==-1 || s2[i]==s2[j]){ i++; j++; nexts[i] = j; } else j = nexts[j]; } return; } int main(){ while(~scanf("%lld%lld",&n,&m)){ scanf("%s",s); int l=strlen(s);p2=0; int i; for(i=0;i<l;i++){ if(s[i]=='.'){ break; } } for(int k=l-1;k>i;k--){ s2[p2++]=s[k]; } GetNext(p2); ll maxx=-1e18; for(i=1;i<=p2;i++){ maxx=max(maxx,(ll)i*n-(ll)(i-nexts[i])*m); //cout<<i<<" "<<(i-nexts[i])<<endl; } printf("%lld ",maxx); } return 0; }
kmp模板
inline void getnext(char *ss){ mem(ne,0); int l=strlen(ss); int i=0,j=-1;ne[0]=-1; while(i<l){ if (j == -1 || ss[i] == ss[j]) { i++; j++; ne[i] = j; } else{ j = ne[j]; } } return; } inline int kmp(char *ss,char *s){ int l=strlen(s),ls=strlen(ss); int i=0,j=0,ans=0; while(i<l){ if(j==-1||s[i]==ss[j]) { i++; j++; } else j=ne[j]; if(j==ls) { ans++; j=ne[j]; } } return ans; }
待补全
模板
int next[maxn]; string str[maxn]; void get_next(string s){ memset(next,0,sizeof(next)); int len=s.length(); int i,j; j=next[0]=-1; i=0; while(i<len){ while(j!=-1&&s[i]!=s[j]) j=next[j]; next[++i]=++j; } } bool kmp(string a,string b){ int lena=a.length(); int lenb=b.length(); get_next(b); int i=0,j=0; while(i<lena){ while(j!=-1&&a[i]!=b[j]) j=next[j]; i++,j++; if(j>=lenb) return true; } return false; }