题目描述
Koishi 决定走出幻想乡成为数学大师!
Flandre听说她数学学的很好,就给Koishi出了这样一道构造题:
Task1:试判断能否构造并构造一个长度为
n
n
n 的
1
…
n
1 \ldots n
1…n 的排列,满足其
n
n
n 个前缀和在模
n
n
n 的意义下互不相同
Taks2:试判断能否构造并构造一个长度为
n
n
n 的
1
…
n
1 \ldots n
1…n 的排列,满足其
n
n
n 个前缀积在模
n
n
n 的意义下互不相同
按照套路,Koishi假装自己根本不会捉,就来找你帮忙辣。
输入格式
第一行两个整数
X
X
X 和
T
T
T,分别表示
T
a
s
k
Task
Task 类型和测试点内的数据组数。
接下来
T
T
T 行,每行一个整数表示每组数据中的
n
n
n
输出格式
为了方便SPJ的编写,您需要遵从以下格式输出。
对于每组数据仅包含一行输出:
如果您认为当前数据不存在符合题意的构造,只需输出一个整数
0
0
0
如果您认为当前数据存在符合题意的构造却不会构造,只需输出一个整数
1
1
1
如果您认为当前数据存在符合题意的构造并成功构造,则需要先输出一个整数
2
2
2,再输出
n
n
n 个整数表示构造的方案。
每两个整数之间需要有空格作为分隔符
输入输出样例
输入 #1
1 1
8
输出 #1
2 8 7 6 5 4 3 2 1
输入 #2
2 1
11
输出 #2
2 1 2 3 5 10 6 7 4 9 8 11
思路
先来考虑 task1 ,我们根据题意简单分析可以知道,
n
n
n 肯定放第一位,不然 它 和 前一位的 前缀和在模
n
n
n 的意义下肯定相同,然后接下来如果没有思路的话可以先暴力一波。
1
:
1
1:1
1:1
2
:
2
1
2:2~~1
2:2 1
3
:
3:
3:
4
:
4
1
2
3
、
4
3
2
1
4:4~~1~~2~~3、4~~3~~2~~1
4:4 1 2 3、4 3 2 1
5
:
5:
5:
6
:
6
1
4
3
2
5
、
6
2
5
3
1
4
、
…
6:6~~1~~4~~3~~2~~5、6~~2~~5~~3~~1~~4、\ldots
6:6 1 4 3 2 5、6 2 5 3 1 4、…
7
:
7:
7:
8
:
8
1
6
3
4
5
2
7
、
…
8:8~~1~~6~~3~~4~~5~~2~~7、\ldots
8:8 1 6 3 4 5 2 7、…
可以明显看出,除了
1
1
1 的奇数好像都没有答案,这里再细致分析一下发现,对于除了
1
1
1 以外的奇数
∑
i
=
1
n
−
1
=
n
∗
(
n
−
1
)
2
=
n
−
1
2
∗
n
\sum_{i=1}^{n-1}=\frac{n*(n-1)}{2}=\frac{n-1}{2}*n
i=1∑n−1=2n∗(n−1)=2n−1∗n
1...
n
1...n
1...n 的和是
n
n
n 的倍数,这样子不管如何排列最后肯定会至少出现两个位置的前缀和模
n
n
n 意义下为
0
0
0,所以除
1
1
1 以外的奇数 task1 无解,那么对于偶数,
n
n
n 越大,答案越多,但是我们仔细观察一下暴力出来的结果
2
:
2
1
2:2~~1
2:2 1
4
:
4
1
2
3
4:4~~1~~2~~3
4:4 1 2 3
6
:
6
1
4
3
2
5
6:6~~1~~4~~3~~2~~5
6:6 1 4 3 2 5
8
:
8
1
6
3
4
5
2
7
8:8~~1~~6~~3~~4~~5~~2~~7
8:8 1 6 3 4 5 2 7
可以总结如下:
n
,
1
,
n
−
2
,
3
,
n
−
4
,
5
,
.
.
.
,
n
−
1
n,1,n-2,3,n-4,5,...,n-1
n,1,n−2,3,n−4,5,...,n−1
换一种写法
i
∈
o
d
d
,
a
i
=
n
+
1
−
i
;
i \in odd,a_i=n+1-i;
i∈odd,ai=n+1−i;
i
∈
e
v
e
n
,
a
i
=
i
−
1
;
i \in even,a_i=i-1;
i∈even,ai=i−1;
这样子 task1 就解决了。
再来考虑 task2,简答分析一下发现,
1
1
1 肯定得放在最前面,不然 它 和前一位 的前缀积在模
n
n
n 的意义下肯定相同,然后
n
n
n 肯定得放在最后面,因为 它 和之后所有位置的前缀积在模
n
n
n 的意义下都为
0
0
0,然后就好像没有思路了,再暴力一波:
1
:
1
1:1
1:1
2
:
1
2
2:1~~2
2:1 2
3
:
1
2
3
3:1~~2~~3
3:1 2 3
4
:
1
3
2
4
4:1~~3~~2~~4
4:1 3 2 4
5
:
1
2
4
3
5
、
1
3
4
2
5
5:1~~2~~4~~3~~5、1~~3~~4~~2~~5
5:1 2 4 3 5、1 3 4 2 5
6
:
6:
6:
7
:
1
2
5
6
3
4
7
、
1
3
4
6
2
5
7
、
1
4
3
6
5
2
7
、
1
5
2
6
4
3
7
7:1~~2~~5~~6~~3~~4~~7、1~~3~~4~~6~~2~~5~~7、1~~4~~3~~6~~5~~2~~7、1~~5~~2~~6~~4~~3~~7
7:1 2 5 6 3 4 7、1 3 4 6 2 5 7、1 4 3 6 5 2 7、1 5 2 6 4 3 7
8
:
8:
8:
除了
4
4
4 以外的合数好像无解,我们据此推一下
n
n
n 为合数的情形,发现一定存在
n
=
a
∗
b
,
a
>
1
,
b
>
1
n=a*b,a>1,b>1
n=a∗b,a>1,b>1 ,还有
n
=
n
n=n
n=n 本身,这样的话,无论何种排列,至少会出现两个位置前缀积模
n
n
n 意义下为
0
0
0 的情况,而
n
=
4
n=4
n=4 有解也可以顺便看出来是因为
4
=
2
∗
2
,
a
=
b
4=2*2,a=b
4=2∗2,a=b 的缘故,所以可以知道除
4
4
4 外仅质数有解。那么如何构造这个解的序列呢?上面的暴力好像看不出什么名堂来,我们把它们做一下前缀积模
n
n
n
2
:
1
2
2:1~~2
2:1 2
3
:
1
2
3
3:1~~2~~3
3:1 2 3
5
:
1
2
3
4
5
、
1
3
2
4
5
5:1~~2~~3~~4~~5、1~~3~~2~~4~~5
5:1 2 3 4 5、1 3 2 4 5
7
:
1
2
3
4
5
6
7
、
1
3
5
2
4
6
7
、
1
4
5
2
3
6
7
、
1
5
3
4
2
6
7
7:1~~2~~3~~4~~5~~6~~7、1~~3~~5~~2~~4~~6~~7、1~~4~~5~~2~~3~~6~~7、1~~5~~3~~4~~2~~6~~7
7:1 2 3 4 5 6 7、1 3 5 2 4 6 7、1 4 5 2 3 6 7、1 5 3 4 2 6 7
发现前缀积模
n
n
n 下都存在
1
,
2
,
.
.
.
,
n
−
1
,
0
1,2,...,n-1,0
1,2,...,n−1,0 的形式,即
m
u
l
i
≡
i
(
m
o
d
n
)
mul_i \equiv i~(mod~~n)
muli≡i (mod n)
设答案序列为
a
n
s
ans
ans,则
m
u
l
i
≡
(
i
−
1
)
×
a
n
s
i
≡
i
(
m
o
d
n
)
mul_i \equiv (i-1) \times ans_i \equiv i~(mod~~n)
muli≡(i−1)×ansi≡i (mod n)
那么对于每个
m
u
l
i
mul_i
muli ,求一下逆元就可以了。
#include<bits/stdc++.h>
using namespace std;
const int N = 1E5+10;
typedef long long ll;
int X,T,n;
int p[N],np[N],cnt;
void Prime()
{
np[1]=1;
for(int i=2;i<N;i++)
{
if(!np[i]) p[++cnt]=i;
for(int j=1;j<=cnt&&i*p[j]<N;j++)
np[i*p[j]]=1;
}
}
ll q_pow(ll x,ll m)
{
ll res=1;
while(m)
{
if(m&1) res=res*x%n;
m>>=1;
x=x*x%n;
}
return res;
}
int main()
{
scanf("%d%d",&X,&T);
if(X==2) Prime();
while(T--)
{
scanf("%d",&n);
if(X==1)
{
if(n>1 && n&1) puts("0");
else
{
putchar('2');
for(int i=1;i<=n;i++)
{
if(i&1) printf(" %d",n+1-i);
else printf(" %d",i-1);
}
puts("");
}
}
else
{
if(np[n]&&n!=1&&n!=4) puts("0");
else{
if(n==1) puts("2 1");
else if(n==4) puts("2 1 3 2 4");
else{
putchar('2');
ll sum=1,tmp=1;
for(int i=1;i<=n-1;i++)
{
printf(" %d",tmp);
tmp=q_pow(sum,n-2)*(i+1)%n;
sum=sum*tmp%n;
}
printf(" %d\n",n);
}
}
}
}
}