【美团杯2020】平行四边形

题:http://uoj.ac/problem/525

分析:1 . 答案是(i,g^i%(n+1))后一项为原根的次方。采用反证法,假设有4个点:(a,g^a),(b,g^b),(c,g^c),(d,g^d);

   2 . 若形成平行四边形则要满足:(1) a-b==c-d. (2)g^a-g^b==g^c-g^d   (    化简为 g^b ( g^(a-b) - 1 ) == g^d ( g^(c-d) -1)   )

   3 . 联立(1)(2)得必须a==c&&b==d才能形成平行四边形,而我们第一项的 i 避免了这一点,所以直接求n+1的原根

#include<bits/stdc++.h>
#define lowbit(i) i&(-i)
#define pb push_back
using  namespace std;
typedef long long ll;
ll ksm(ll a,ll b,ll mod){
    ll t=1;
    while(b){
        if(b&1)
            t=t*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return t;
}
///求原根
ll solve(ll p,ll m){///p==phi(m)
    ll x=p;
    vector<ll>tmp;
    tmp.clear();
    for(ll i=2;i*i<=x;i++){
        if(x%i==0){
            tmp.pb(i);
            while(x%i==0)
                x/=i;
        }
    }
    if(x>1)
        tmp.pb(x);
    for(ll i=2;;i++){
        ll flag=1;
        for(auto x:tmp){
            if(ksm(i,p/x,m)==1){
                flag=0;
                break;
            }
        }
        if(flag)
            return i;
    }
    return -1;
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        ll n;
        scanf("%lld",&n);
        ll g=solve(n,n+1);
        if(g==-1){
            printf("-1\n");
        }
        else{
            for(ll i=1;i<=n;i++)
                printf("%lld %lld\n",i,ksm(g,i,n+1));
        }
    }
    return 0;
}
View Code

 

posted @ 2020-05-27 23:02  starve_to_death  阅读(193)  评论(0编辑  收藏  举报