【美團杯2020】平行四邊形(原根)

【美團杯2020】平行四邊形

蒜斜非常喜歡下圍棋。自從AlphaOg面世以來,他就立志一定要研究出AlphaOg的破綻。 終於,他發現當AlphaOg遇到一種特殊局面後,它的神經網絡會自動輸出“投降”!

隨着進一步的研究,蒜斜發現這種局面有着更一般的特性,不僅僅侷限於固定大小棋盤。 具體來說,當棋盤大小是 n(n+1 是一個質數)且棋盤上恰好有 n 個棋子的時候,如果這些棋子的位置滿足下列條件,那麼 AlphaOg 就會直接投降。假設第 i 個棋子的位置是點 Pi,處在第 xi 行第 yi 列,那麼這些座標需要滿足:

x1 至 xn 是 1−n 的排列。
y1 至 yn 是 1−n 的排列。
這些點之間不構成平行四邊形(包括退化)。即對於任何兩個不完全相同的棋子對 (Pa,Pb),(Pc,Pd)(允許它們之間共用至多一個棋子),線段 PaPb 與 PcPd 要麼長度不同,要麼所在的直線不平行且不重合。
憑藉這項發現,蒜斜榮獲了“北大算協吉祥物”的稱號。 如果你也能找出一種合法方案,蒜斜的稱號就是你的了!

輸入格式
輸入第一行包含一個整數 t(1≤t≤10),表示數據組數。

對於每組數據,輸入第一行包含一個整數 n(4≤n≤1000),保證 n+1 是一個質數。

輸出格式
對於每組數據,如果無解輸出一行一個整數 -1。否則輸出 n 行,每行兩個整數 (xi,yi)(1≤xi≤n,1≤yi≤n),表示第 i 個棋子的座標。如果座標方案不唯一,你只需要輸出任意一種。

樣例一
input

1
4

output
1 1
3 2
4 3
2 4

限制與約定
Small Task: n≤12。

Large Task: n≤1000。

時間限制:1s
空間限制:512MB

一個n*n棋盤(n+1爲奇質數)每行和每列有且只有一個棋子,且沒有四個棋子可以構成一個平行四邊形,求任意一組解

  • 原根簡單介紹:
    • 如果m爲奇質數一定存在模m的原根.
    • 原根的性質:假設一個數g是m的原根,那麼gi mod m的結果兩兩不同,且有 1<g<m,0<i<m
    • 原根的求法:如果g是m的原根,gi = 1 (mod m)當且僅當i=m-1的時候成立
  • 先求出模n+1的原根g,答案就是(1,g mod(n+1)),(2,g2 mod(n+1)),(3,g3 mod(n+1))…(n,gn mod(n+1))
  • 正確性證明:
    • 假設四個可以構成平行四邊形的點爲(a,ga)(b,gb),(c,gc),(d,gd)
    • 四個點構成平行四邊形,當且僅當滿足以下兩個條件
    • 1、a-b=c-d
    • 2、ga-gb=gc-gd <==> ga(1-gb-a) = gc(1-gd-c) <==> ga=gc
    • 根據原根的性質,當a!=c時ga!=gc,結論和假設矛盾
    • 所以就證明了不會構成平行四邊形
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e3+9;
long long qui_pow(long long a,long long n,long long mod)
{
    long long ans = 1;
    while(n)
    {
        if(n&1)
            ans = ans*a%mod;
        a=a*a%mod;
        n>>=1;
    }
    return ans;
}
bool judge(long long a,long long n)
{
    for(long long i = 1; i<n; i++)
    {
        long long num = qui_pow(a,i,n)%n;
        if(i!=n-1&&num==1)
            return 0;
        if(i==n-1&&num!=1)
            return 0;
    }
    return 1;
}

int main()
{
    ios::sync_with_stdio(false);
    long long i,j,n,m,t,num;
    cin>>t;
    while(t --)
    {
        cin>>n;
        num = -1;
        for(i = 1; i<n; i++)
        {
            if(judge(i,n+1))
            {
                num = i;
                break;
            }
        }
        for(i = 1;i<=n;i++)
        {
            printf("%lld %lld\n",i,qui_pow(num,i,n+1)%(n+1));
        }
    }

    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章