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;
}
posted @ 2020-07-24 20:35  GK0328  阅读(69)  评论(0编辑  收藏  举报