题目
T
a
s
k
1
Task1
Task1:构造一个长度为
n
n
n的
1
…
n
1\dots n
1…n的排列,满足其
n
n
n个前缀和在模
n
n
n的意义下互不相同
T
a
k
s
2
Taks2
Taks2:构造一个长度为
n
n
n的
1
…
n
1\dots n
1…n的排列,满足其
n
n
n个前缀积在模
n
n
n的意义下互不相同
分析
T
a
s
k
1
Task1
Task1:
除了奇数1和偶数,其它都不可构造。
因为
n
∣
n
n|n
n∣n,所以
n
n
n必须为第一个,
1
∼
n
1\sim n
1∼n的和为
n
(
n
+
1
)
2
\frac{n(n+1)}{2}
2n(n+1),所以如果是非1的奇数,和第一个前缀和模
n
n
n意义下相同,故无解
答案怎么样,通过一系列的打表可以发现答案可以为
n
,
1
,
n
−
2
,
3
,
n
−
4
,
5
,
…
n,1,n-2,3,n-4,5,\dots
n,1,n−2,3,n−4,5,…
T
a
s
k
2
Task2
Task2:
除了合数4,其它合数都无解。
因为最后的前缀积为
n
!
n!
n!,所以说
n
n
n为最后一位,而且
n
∤
(
n
−
1
)
!
n\nmid(n-1)!
n∤(n−1)!。所以
n
n
n只能为4或质数(还有特殊的1)
那么除了最后一个为
n
n
n,每一个答案就是
i
i
−
1
\frac{i}{i-1}
i−1i的逆元。
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
int q,n; long long f[100001];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline bool is_prime(int n)
{
if(n==2||n==3) return 1;
if(n%6!=1&&n%6!=5) return 0;
for(int i=5;i*i<=n;i+=6)
if(n%i==0 || n%(i+2)==0) return 0;
return 1;
}
signed main(){
q=iut();
if (q&1){
for (rr int t=iut();t;--t){
n=iut();
if (n==1) printf("2 1\n");
else if (n&1) printf("0\n");
else{
printf("2");
for (rr int i=0;i<(n>>1);++i) printf(" %d %d",n-(i<<1),i<<1|1);
printf("\n");
}
}
}
else{
for (rr int t=iut();t;--t){
n=iut();
if (n==1) printf("2 1\n");
else if (n==4) printf("2 1 3 2 4\n");
else if (is_prime(n)){
f[1]=1; printf("2 1");
for (rr int i=2;i<=n;++i)
f[i]=f[n%i]*(n-n/i)%n;
for (rr int i=2;i<n;++i)
printf(" %lld",f[i-1]*i%n);
printf(" %d\n",n);
}
else printf("0\n");
}
}
return 0;
}