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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值