题目
Koishi决定走出幻想乡成为数学大师!
Flandre听说她数学学的很好,就给Koishi出了这样一道构造题:
Task1:试判断能否构造并构造一个长度为n的1…n的排列,满足其n个前缀和在模n的意义下互不相同
Taks2:试判断能否构造并构造一个长度为n的1…n的排列,满足其n个前缀积在模n的意义下互不相同
按照套路,Koishi假装自己根本不会捉,就来找你帮忙辣。
n<=1e6
思路
task1:
首先n是奇数且n!=1肯定不行,因为
n
∣
n
∗
(
n
−
1
)
2
n|\frac{n*(n-1)}{2}
n∣2n∗(n−1) 显然无解。
然后我们发现n一定要放第一位,因为n%n=0
考虑怎么构造:首先我们假定前缀和是1,-1,2,-2,3,-3……(mod n)
然后发现这样构造的数集正好是1……n-1的排列
这就做完了
task2:
首先1一定要放最前面,n一定要放最后面,因为序列要保证任何的前缀(除了最后一个)都>0。
于是我们发现非1和4的非质数一定无解,因为前面一定会出现0。
那么质数我们就可以求逆元啦
特判一下1和4就行。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int T,n;
void Solve1()
{
while(T--)
{
scanf("%d",&n);
if(n==1)
{
printf("2 1\n"); continue;
}
if(n&1==1)
{
printf("0\n"); continue;
}
printf("2 %d ",n);
for(int i=1; i<n; i++)
{
if(i&1==1) printf("%d ",i);
else printf("%d ",n-i);
}
printf("\n");
}
}
bool check(int x)
{
for(int i=2; i<=sqrt(x); i++) if(x%i==0) return 0;
return 1;
}
ll inv[100005];
void Solve2()
{
while(T--)
{
scanf("%d",&n);
if(check(n))
{
printf("2 1 ");
inv[1] = 1;
for(int i=2; i<=n-1; i++)
{
inv[i]=(ll)(n-n/i)*inv[n%i]%n;
printf("%d ",(inv[i-1]*i+n)%n);
}
if(n!=1) printf("%d\n",n);
}
else if(n==4) printf("2 1 3 2 4\n");
else printf("0\n");
}
};
int main()
{
int x;
scanf("%d%d",&x,&T);
if(x==1) Solve1();
else Solve2();
}