【美團杯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;
}