洛谷P3599 Koishi Loves Construction 题解
题目链接:P3599 Koishi Loves Construction
题意
Koishi 决定走出幻想乡成为数学大师!
Flandre 听说她数学学的很好,就给 Koishi 出了这样一道构造题:
Task1:试判断能否构造并构造一个长度为 $n$ 的 $1 \dots n$ 的排列,满足其 $n$ 个前缀和在模 $n$ 的意义下互不相同。
Task2:试判断能否构造并构造一个长度为 $n$ 的 $1 \dots n$ 的排列,满足其 $n$ 个前缀积在模 $n$ 的意义下互不相同。
按照套路,Koishi 假装自己根本不会做,就来找你帮忙辣!
输入格式:
第一行两个整数 $X$ 和 $T$,分别表示 Task 类型和测试点内的数据组数。
接下来 $T$ 行,每行一个整数表示每组数据中的 $n$。
输出格式:
为了方便 SPJ 的编写,您需要遵从以下格式输出。
对于每组数据仅包含一行输出:
- 如果您认为当前数据不存在符合题意的构造,只需输出一个整数 $0$。
- 如果您认为当前数据存在符合题意的构造却不会构造,只需输出一个整数 $1$。
- 如果您认为当前数据存在符合题意的构造并成功构造,则需要先输出一个整数 $2$,再输出 $n$ 个整数表示构造的方案。
每两个整数之间需要有空格作为分隔符。
数据范围:
对于所有测试点,满足 $1 \leq T \leq 10,~X=1,2,~1 \le n \le 10^5$ 。
第一问,考虑构造 $1,\,-2,\,3,\,-4,\,\cdots$ ,这样前缀和就是 $1,-1,2,-2,\cdots$ 。
第二问,可以发现
- 不能有区间 $[l,r]$ 的积 $\equiv 1\pmod{n}$ ,其中 $l > 1$ 。
- 不能有区间 $[l,r]$ 的积 $\equiv 0\pmod{n}$ ,其中 $r < n$ 。
- $n \not\mid (\prod_{i=1}^{n-1}i)$ ,否则肯定凑不出来。
于是显然有 $a_1=1,~a_n=n$ 。并且从第三条可以发现 $n$ 为质数时有解(除了 $n=1$ 和 $n=4$ 的情况)
记 $p_i = \prod_{j=1}^ia_j$ ,那么构造一种方案使得 $p_i \equiv i \pmod{n}$ 即可,可以求逆元构造。
时间复杂度 $\mathcal{O}(n \log n)$
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x, int y) { x < y ? x = y : 0; }
void down(int &x, int y) { x > y ? x = y : 0; }
#define rep(i, a, b) for(int i = (a), i##END = (b); i <= i##END; i++)
#define Rep(i, a, b) for(int i = (a), i##END = (b); i >= i##END; i--)
#define N ((int)())
bool is_pri(int x)
{
for(int i = 2; i * i <= x; i++)
if(x % i == 0) return false;
return true;
}
int qpow(int a, int b, int mod)
{
int r = 1;
for(a %= mod; b; b >>= 1, a = a * a % mod)
if(b & 1) r = r * a % mod;
return r;
}
void solve1()
{
int n; cin >> n; if((n & 1) && (n != 1)) { return cout << "0\n", void(0); }
cout << "2 "; rep(i, 1, n) cout << (i & 1 ? n + 1 - i : i - 1) << " \n"[i == n];
}
void solve2()
{
int n; cin >> n;
if(n == 1) { return cout << "2 1\n", void(0); }
if(n == 4) { return cout << "2 1 3 2 4\n", void(0); }
if(!is_pri(n)) { return cout << "0\n", void(0); }
cout << '2';
for(int i = 1, x = 1, prod = 1; i < n; i++)
{
cout << ' ' << x;
x = qpow(prod, n - 2, n) * (i + 1) % n; prod = prod * x % n;
}
cout << ' ' << n << '\n';
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
// freopen("check.in","r",stdin);
// freopen("check.out","w",stdout);
int cxy, qwq; cin >> cxy >> qwq;
while(qwq--) { cxy - 1 ? solve2() : solve1(); }
return 0;
}
参考文献: