Problem J – Jumping Frog(0~n-1跳k==跳gcd(n,k))

原题: https://cn.vjudge.net/problem/Gym-101889J

题意:

0~n-1点一圈,有些点可以跳,有些不可以。现在你可以选一个点为起点,每次跳k,直到回到起点。问有多少个k可以跳回起点。

解析:

证明:0~n-1的圈每次跳k步,如果k,n互质那么会跳过所有点0 ~n-1

跳过的点应该是ak%n(a为倍数),发现只有a=n时也就是跳到lcm(k,n)=k*n的时候才会回到起点,那么途中经过n个点,因为所有点无循环即只出现一次,所以可以得出n个点即所有点,证毕。


证明: 每次跳k步和每次跳gcd(n,k)步,遇到的所有点的集合一样

每次跳到的点为:

( a k ) % n = ( ( a k g c d ( n , k ) ) % n ∗ g c d ( n , k ) ) % n ( a 为 倍 数 , 取 任 意 整 数 )    n 与 k g c d ( n , k ) 互 质 , 所 以 ( a k g c d ( n , k ) ) % n 可 以 取 到 [ 0 , n − 1 ]    也 就 变 成 了 a ∗ k % n = b ∗ g c d ( k , n ) % n , 证 毕 (ak)\%n= ((a\frac{k}{gcd(n,k)})\%n*gcd(n,k))\%n(a为倍数,取任意整数)\\\;\\n与\frac{k}{gcd(n,k)}互质,所以(a\frac{k}{gcd(n,k)})\%n可以取到[0,n-1]\\\;\\也就变成了a*k\%n=b*gcd(k,n)\%n,证毕 (ak)%n=((agcd(n,k)k)%ngcd(n,k))%nangcd(n,k)k(agcd(n,k)k)%n[0,n1]ak%n=bgcd(k,n)%n


那么这题其实已经结束了,枚举所有k,那么就可以归纳所有的gcd,这个数量最多为一个数的因子数。(这个数量非常有限,一个数的素因子个数为10数量级,因子个数为100数量级,1000000以内最多的720720有240个因子,10000000里的8648640为448个)

那么接下来就是暴力每个gcd

#include
using namespace std;


char x[100009];

int k[100009];
bool vis[100009];

int main(){
    scanf("%s",x);
    int n=strlen(x);
    for(int i=1;i<n;i++){
        k[__gcd(n,i)]++;
    }
    int ans=0;

    for(int i=1;i<n;i++){
        if(n%i)continue;
        memset(vis,0,sizeof(vis));
        for(int j=0;j<n;j++){
        	//因为gcd=i为n的因子,所以跳到的点为a+ki
            if(x[j]=='P')vis[j%i]=1;//kx+j如果不行,说明j这个点也不行
        }
        int yes=0;
        for(int j=0;j<i;j++){
            if(vis[j]==0){
                yes=1;break;
            }
        }
        if(yes)ans+=k[i];
    }
    printf("%d\n",ans);
}

你可能感兴趣的:(想法题)