题解 Gym101889J 【Jumping frog】

突然发现题刷累了写写题解还是满舒服

题目大意:

给你一个只包含 \(R\)\(P\) ,长度为 \(n\) 的字符串( \(3\le n\le 10^5\) )。你可以选择一个跳跃距离 \(l\)\(1\le l\le n-1\) ),并对于每一种跳跃距离,你可以随意选择一个起点,进行若干次跳跃后回到起点(字符串首尾相接构成一个环),问有多少种距离是满足存在一种跳跃情况使得期间没有经过 \(P\)

题解:

经过若干次尝试,我们可以轻易的发现,任意一个跳跃距离 \(l\) ,他完全等价与跳跃距离为 \(gcd(l,n)\) 的情况,也就是说,我们如果可以判断出 \(n\) 的所有可能的 \(gcd\) ,再判断,同时计算出与 \(n\) 有着此 \(gcd\) 的数的个数,我们就可以计算答案了。

\(n\) 的所有可能的 \(gcd\) 就是 \(n\) 的因数,我们可以用线性筛筛素数,再分解质因数,最后得出所有的因数并判断,复杂度在 \(O(n\sqrt{n})\) 左右。

然后我们考虑如何得出对于每一种因数,有多少个数与 \(n\)\(gcd\) 为它。我们设 \(gcd(l,n)=x\) ,易得 \(gcd(l/x,n/x)=1\) ,所以我们就相当于求在 \(1\sim n/x-1\) 中,有多少个数与 \(n/x\) 互质,这不就是 $\varphi $ 函数吗?处理 $\varphi $ 函数可以放在线性筛中,这里的复杂度为 \(O(n)\)

总复杂度为 \(O(n\sqrt{n})\) 左右。

作者辛辛苦苦写完了题解,才发现可以直接 \(dp\) ,不需要这么麻烦,枯了。

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
char s[N];
int len;
int eul[N],pri[N],lpri=0;
int cnt[N];
bool vis[N];
int ans=0;
int gcd(int a,int b)
{
    if(b==0)
    return a;
    return gcd(b,a%b);
}
bool tag[N];
void dfs(int now,int sum)
{
    if(now>lpri)
    {
        if(len%sum)
        return ;
        int cnt=sum;
        memset(tag,0,sizeof(tag));
        for(int i=1;i<=len;++i)
        {
            if(s[i]=='R')
            continue;
            if(!tag[i%sum])
            {
                tag[i%sum]=true;
                --cnt;
            }
        }
        if(cnt)
        ans+=eul[len/sum];
        return ;
    }
    int tmp=1;
    for(int i=0;i<=cnt[now];++i)
    {
        dfs(now+1,sum*tmp);
        tmp*=pri[now];
    }
    return ;
}
int main()
{
    scanf("%s",s+1);
    len=strlen(s+1);
    for(int i=2;i<=len;++i)
    {
        if(!vis[i])
        {
            eul[i]=i-1;
            pri[++lpri]=i;
        }
        for(int j=1;j<=lpri;++j)
        {
            if(i*pri[j]>len)
            break;
            vis[i*pri[j]]=true;
            if(i%pri[j])
            eul[i*pri[j]]=eul[i]*eul[pri[j]];
            else
            {
                eul[i*pri[j]]=eul[i]*pri[j];
                break;
            }
        }
    }
    int tmp=len;
    for(int i=1;i<=lpri;++i)
    {
        while(tmp%pri[i]==0)
        {
            tmp/=pri[i];
            ++cnt[i];
        }
    }
    dfs(1,1);
    printf("%d\n",ans);
}

猜你喜欢

转载自www.cnblogs.com/Point-King/p/13374157.html