洛谷 P3599 Koishi Loves Construction
洛谷 P3599 Koishi Loves Construction
思路
一道构造好题。
Task1
能够看出两点:
-
第一个数必须是 \(n\)。
因为有 \(x+n\equiv x(\bmod n)\),如果第一个数不是 \(n\),必然会有两个相邻的前缀和模 \(n\) 的值相等。
-
除了 \(1\) 之外的奇数都不存在正确构造。
当 \(n\) 为奇数时,有
\[\sum\limits_{i=1}^{n-1}i\mod n=\dfrac{n\times(n-1)}{2}\mod n=0 \]因为已经确定了第一个数为 \(n\),所以一定会冲突。
剩下的 \(n-1\) 个数,可以找到一种为 \(\text{1 -2 3 -4 5...}\) 的方案,保证 \(1\sim n - 1\) 的所有数都能出现,因为这样的话前缀和在模 \(n\) 意义下获得的数就是 \(1\sim n - 1\),然后负数要转化为正数,最后的序列就能够保证每个数只出现了一次。
代码里的实现是先输出第一个数 \(n\),然后输出第 \(2\sim n\) 个数,如果 \(i\mod2 = 1\) 则输出 \(n+1-i\),否则输出 \(i-1\)。
Task2
容易看出:
-
\(n\) 只能是最后一个数。
若 \(n\) 不为最后一个数,那么在 \(n\) 之后的前缀积在模 \(n\) 意义下一定为 \(0\),必定会冲突。
剩下的数,我们的目标是构造一个在模 \(n\) 意义下前缀积连续递增的序列。
那么一种可行的构造方案是 \(1,\frac{2}{1},\frac{3}{2}...\frac{n}{n-1}\),因此我们只需要求出每个数的逆元,输出即可。
但是会有无解的情况,那就是不为 \(4\) 的合数一定无解,因为如果 \(n\) 是合数,那么一定存在小于 \(n\) 的两个数乘积为 \(n\),所以只有 \(1,4\) 和所有的质数有解。
注意看特判 \(1\) 和 \(4\) 的情况,因为 \(4\nmid 3!\)。
代码
/*
Name: P3599 Koishi Loves Construction
Author: Loceaner
Date: 08/09/20 11:24
*/
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int A = 1e5 + 11;
const int B = 1e6 + 11;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int opt, T, inv[A];
inline bool judge(int x) {
for (int i = 2; i * i <= x; i++) {
if (x % i == 0) return 0;
}
return 1;
}
signed main() {
opt = read(), T = read();
while (T--) {
int n = read();
if (opt == 1) {
if (n % 2 && n != 1) puts("0");
else {
cout << 2 << " ";
cout << n << " ";
for (int i = 2; i <= n; i++) {
if (i % 2) cout << n + 1 - i << " ";
else cout << i - 1 << " ";
}
puts("");
}
}
if (opt == 2) {
if (n == 1) {
puts("2 1");
continue;
}
if (n == 4) {
puts("2 1 3 2 4");
continue;
}
if (!judge(n)) puts("0");
else {
int mod = n;
inv[0] = inv[1] = 1;
for (int i = 2; i < n; i++) inv[i] = mod - (mod / i) * inv[mod % i] % mod;
cout << 2 << " ";
for (int i = 1; i < n; i++) cout << i * inv[i - 1] % mod << " ";
cout << n << '\n';
}
}
}
}
转载不必联系作者,但请声明出处