1. 程式人生 > 實用技巧 >2017-2018 ACM-ICPC Latin American Regional Programming Contest J - Jumping frog 題解(gcd)

2017-2018 ACM-ICPC Latin American Regional Programming Contest J - Jumping frog 題解(gcd)

題目連結

題目大意

 一隻青蛙在長度為N的字串上跳躍,“R”可以跳上去,“P”不可以跳上去。

 字串是環形的,N-1和0相連。

 青蛙的跳躍距離K的取值範圍是[1, N-1],選定K之後不可改變。

 要求青蛙最後能跳回起點(起點可以是0-N-1的任意一個位置),問K的取值有多少種選擇。

 \(3≤N≤{10}^5\)

題目思路

主要是要發現每一次走的步數一定是gcd(i,n)

然後發現gcd只有log(n)(可能多一些,但是沒多太大)

然後O(n) check

程式碼

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#define fi first
#define se second
//#define int long long
#define debug printf(" I am here\n");
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
const double eps=1e-10;
char s[maxn];
int n;
int vis[maxn];
int gcd(int a,int b){
    return b==0?a:gcd(b,a%b);
}
bool check(int x){
    for(int i=1;i<=x;i++){
        bool flag=1;
        for(int j=i;j<=n;j+=x){
            if(s[j]=='P'){
                flag=0;
                break;
            }
        }
        if(flag) return 1;
    }
    return 0;
}
signed main(){
    memset(vis,-1,sizeof(vis));
    scanf("%s",s+1);
    n=strlen(s+1);
    int ans=0;
    for(int i=1;i<=n-1;i++){
        int x=gcd(i,n);
        if(vis[x]==-1){
            if(check(x)){
                vis[x]=1;
            }else{
                vis[x]=0;
            }
        }
        ans+=vis[x];
    }
    printf("%d\n",ans);
    return 0;
}