链接:I.Slot Machines
题意:
每次给出数组 a 。问要满足从第k+1个数开始,数组T开始以p个数为一个循环,k+p最小是多少。如果存在多个k+p最小,输出p最小的方案。
思路:
- 枚举每一个 k 求出 [k + 1 , n] 的循环节长度就好了 , 可以用 kmp 求出循环节长度 , 我们先求出nex数组 , 对于后 i 个数的 p 值 就是 i - nex[i].
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef long long ll;
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 7;
const int mod = 998244353;
int s[maxn];
int nex[maxn],n;
void getnext(){
nex[0] = -1;
int i = 0,j = -1;
while(i <= n){
if(j == -1 || s[i] == s[j]){
i ++;
j ++;
nex[i] = j;
}
else j = nex[j];
}
}
int cal(int len){ // 计算长度为 前 len 个字符的循环节 , 不一定完整 如abcabca 会返回 3.
return len - nex[len];
}
int main (){
scanf("%d",&n);
for(int i = 0; i < n; i ++){
scanf("%d",&s[i]);
}
reverse(s ,s + n);
getnext();
int ans1,ans2;
for(int i = 1; i <= n; i ++){
if(cal(i) + n - i < ans1 + ans2){
ans1 = cal(i);
ans2 = n - i;
}
else if(cal(i) + n - i == ans1 + ans2){
if(ans1 > cal(i)){
ans1 = cal(i);
}
}
}
printf ("%d %d\n",ans2,ans1);
}
- 如果在某些题里遇到要求最小循环节的题目,我们就要判断总长度是否能被这个 p 整除。
链接: 最小循环节
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef long long ll;
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 7;
const int mod = 998244353;
char s[maxn];
int nex[maxn],n;
int T;
void getnext(){
nex[0] = -1;
int i = 0,j = -1;
while(i <= n){
if(j == -1 || s[i] == s[j]){
i ++;
j ++;
nex[i] = j;
}
else j = nex[j];
}
}
int cal(int len){ // 计算长度为 前 len 个字符的循环节 , 不一定完整 如abcabca 会返回 3.
return len - nex[len];
}
int main (){
scanf("%d",&T);
while(T--){
scanf("%s",s);
memset(nex,0,sizeof(nex));
n = strlen(s);
getnext();
int ans = cal(n);
if(n % ans == 0){
printf ("%d\n",ans);
}
else printf ("%d\n",n);
if(T!=0) printf ("\n");
}
}