【Codeforces986F】 Oppa Funcan Style Remastered

time limit: per test 5 seconds
memory limit: per test 256 megabytes
standard input
standard output

Description
Surely you have seen insane videos by South Korean rapper PSY, such as “Gangnam Style”, “Gentleman” and “Daddy”. You might also hear that PSY has been recording video “Oppa Funcan Style” two years ago (unfortunately we couldn’t find it on the internet). We will remind you what this hit looked like (you can find original description here):

On the ground there are n platforms, which are numbered with integers from 1 to n, on i-th platform there is a dancer with number i. Further, every second all the dancers standing on the platform with number i jump to the platform with the number f(i). The moving rule f is selected in advance and is not changed throughout the clip.

The duration of the clip was k seconds and the rule f was chosen in such a way that after k seconds all dancers were in their initial positions (i.e. the i-th dancer stood on the platform with the number i). That allowed to loop the clip and collect even more likes.

PSY knows that enhanced versions of old artworks become more and more popular every day. So he decided to release a remastered-version of his video.

In his case “enhanced version” means even more insanity, so the number of platforms can be up to 1018 10 18 ! But the video director said that if some dancer stays on the same platform all the time, then the viewer will get bored and will turn off the video immediately. Therefore, for all x from 1 to n f(x)≠x must hold.

Big part of classic video’s success was in that looping, so in the remastered version all dancers should return to their initial positions in the end of the clip as well.

PSY hasn’t decided on the exact number of platforms and video duration yet, so he asks you to check if there is a good rule f for different options.

Input
In the first line of input there is one integer t (1≤t≤104) — the number of options for n and k to check.

In the next t lines the options are given: each option is described with two integers n and k (1n1018,1k1015) ( 1 ≤ n ≤ 10 18 , 1 ≤ k ≤ 10 15 ) — the number of dancers and the duration in seconds.

It is guaranteed that the number of different values of k in one test is not greater than 50.

Output
Print t lines. If the i-th option of the video is feasible, print “YES” (without quotes) in
i-th line, otherwise print “NO” (without quotes).

Example
input1

3
7 7
3 8
5 6

output1

YES
NO
YES

题目大意
求是否存在f[1..n] (f[i]i) ( f [ i ] ≠ i )
每秒钟i会跳到f[i]
使得k秒后个点归回原位


Analysis
转化题意,就是要问是否能用k的非1因子累加得n
进一步思考,则是询问能否通过k的质因子累加得n

对k分解质因数,得 p1,p2,,pk p 1 , p 2 , ⋯ , p k

①k=1,特判
②k=2,ap1+bp2=n,构造一个特解 b=np12(modp1) b = n ∗ p 2 − 1 ( mod p 1 ) ,若此时bp2>n无解
③otherwise,问是否能用多个数构成n,经典问题
不妨令p1最小
设f[x]表示用p2~pk构成模意义下为x的数至少需要的和,这个DP显然可以用最短路去做
最后只用判断f[n%p1]是否不比n大即可

code

#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
#define P 31600000
#define N 100100

using namespace std;

ll f[N];
int pr[P],t,p[N],l,que[N*20],head,tail;
bool bz[P],ans[N],vis[N];
struct qry{ll n,k,w;}q[N];
bool cmp(qry a,qry b){return a.k<b.k;}

ll qpow(ll a,ll i,ll mo){
    ll r=1;for(;i;i>>=1,a=a*a%mo)if(i&1)r=r*a%mo;return r;
}

int main(){
    scanf("%d",&t);
    for(int i=1;i<=t;i++)scanf("%I64d %I64d",&q[i].n,&q[i].k),q[i].w=i;
    sort(q+1,q+t+1,cmp);
    for(int i=2;i<P;i++){
        if(!bz[i])pr[++pr[0]]=i;
        for(int j=1;j<=pr[0] && i*pr[j]<P;j++){
            bz[i*pr[j]]=1;if(i%pr[j]==0)break;
        }
    }
    for(int i=1;i<=t;i++){
        ll n=q[i].n,k=q[i].k;
        if(k!=q[i-1].k){
            l=0;for(int j=1;k>1;j++){
                if((ll)pr[j]*pr[j]>k){p[++l]=k;break;}
                if(k%(ll)pr[j]==0){
                    p[++l]=pr[j];while(k%(ll)pr[j]==0)k/=(ll)pr[j];
                }
            }
        }k=q[i].k;
        if(l==0)ans[q[i].w]=0;else
        if(l==1)ans[q[i].w]=n%k==0;else
        if(l==2){
            ll b=n%(ll)p[1]*qpow(p[2],p[1]-2,p[1])%(ll)p[1];
            ans[q[i].w]=b*(ll)p[2]<=n;
        }else{
            if(k!=q[i-1].k){
                for(int j=1;j<=p[1];j++)f[j]=1e18;f[0]=0;
                for(head=0,vis[que[tail=1]=0]=1;head^tail;){
                    int x,j;
                    for(x=que[++head],j=2;j<=l;j++){
                        ll F=f[x]+p[j];int v=(x+p[j])%p[1];
                        if(F<f[v]){
                            f[v]=F;if(!vis[v])vis[que[++tail]=v]=1;
                        }
                    }vis[x]=0;
                }
            }ans[q[i].w]=f[q[i].n%p[1]]<=q[i].n;
        }
    }
    for(int i=1;i<=t;i++)if(ans[i])printf("YES\n");else printf("NO\n");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值