Gym101889J Jumping frog
https://codeforces.com/gym/101889/attachments
环形DP
显然\(\gcd(i,n)\)相等的\(i\),他们的情况完全一致(都可以由多次跳\(\gcd(i,n)\)步转移而来)
那么我们枚举\(n\)的因数,注意是因数而不是质因数
例如对于\(2\)和\(4\)
\[
2:1 \rightarrow 2 \rightarrow 4\\
4:1 \rightarrow 4
\]
后一种跳过了\(2\),应当分开讨论
先特判\(1\)的情况
然后判断情况是否存在
常规操作,把原串复制一遍
定义\(bool\)类型数组\(dp\),\(dp[i]\)表示跳到\(i\)是否可行
设枚举到因子\(x\)
\[初值:dp[i]=[s[i]='R']\\
转移:dp[i]=dp[i] \& dp[i-x]
\]
\(OK!\)
\(Code:\)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define N 400005
using namespace std;
int n,ans=0,g=0;
char s[N],w[N];
bool vis[N],dp[N];
void ins(int x)
{
for (int i=1;i<=(n << 1);i++)
dp[i]=(w[i]=='R');
for (int i=x+1;i<=(n << 1);i++)
dp[i]&=dp[i-x];
for (int i=n+1;i<=(n << 1);i++)
if (dp[i])
{
vis[x]=true;
return;
}
}
int main()
{
scanf("%s",s);
n=strlen(s);
for (int i=0;i<n;i++)
g+=(int)(s[i]=='P');
if (!g)
{
cout << (n-1) << endl;
return 0;
}
for (int i=1;i<=n;i++)
w[i]=w[i+n]=s[i-1];
for (int i=2;i*i<=n;i++)
if (n%i==0)
{
ins(i);
if (i*i!=n)
ins(n/i);
}
for (int i=1;i<n;i++)
ans+=(int)vis[__gcd(n,i)];
cout << ans << endl;
return 0;
}