Forever Young

洛谷 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';
      }
    }
  }
}
posted @ 2020-09-08 12:45  Loceaner  阅读(259)  评论(0编辑  收藏  举报