Good Bye 2022: 2023 is NEAR

写在前面

比赛地址:https://codeforces.com/contest/1770

研究表明,玩废萌 gal 将会造成老年痴呆。

但是 RJ 的 op 真好听。

upd:虽然没玩,但是皇姬 的 op 真好听。

题面里的 Koxia 和 Mahiru 是两个 v 来着,既然出题人喜欢那就扔一下链接。好久不看 v 了,令人感慨。
真绯瑠Mahiru:https://space.bilibili.com/477306079
恋诗夜Koxia:https://space.bilibili.com/690608690

A

贪心模拟。

//By:Luckyblock
/*
*/
#include <cstdio>
#include <cctype>
#include <algorithm>
#define LL long long
const int kN = 10010;
//=============================================================
int a[kN], b[kN], c[kN];
LL sum;
//=============================================================
inline int read() {
	int f = 1, w = 0; char ch = getchar();
	for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = - 1;
	for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + ch - '0';
	return f * w;
}
//=============================================================
int main() {
  int T = read();
  while (T --) {
    int n = read(), m = read();
    sum = 0;
    for (int i = 1; i <= n; ++ i) a[i] = read();
    for (int i = 1; i <= m; ++ i) b[i] = read();
    for (int i = 1; i <= m; ++ i) {
      int min_a = 1;
      for (int j = 1; j <= n; ++ j) {
        if (a[j] < a[min_a]) min_a = j;
      }
      a[min_a] = b[i];
    }
    for (int i = 1; i <= n; ++ i) sum += a[i];
    printf("%lld\n", sum);
  }
	return 0;
}

B

最小代价为 \(n+1\)

交替排列 \(i\)\(n-i+1\) 即可。

//By:Luckyblock
/*
*/
#include <cstdio>
#include <cctype>
#include <algorithm>
//=============================================================
//=============================================================
inline int read() {
	int f = 1, w = 0; char ch = getchar();
	for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = - 1;
	for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + ch - '0';
	return f * w;
}
//=============================================================
int main() {
	int T = read();
  while (T --) {
    int n = read(), k = read();
    for (int i = 1, j = n; i < j; ++ i, -- j) printf("%d %d ", j, i);
    if (n % 2 == 1) printf("%d ", n / 2 + 1);
    printf("\n");
  }
	return 0;
}

C

\(t\) 组数据,每组数据给定一长度为 \(n\) 的数列 \(a\),要求判断是否存在一个正整数 \(x\),满足:
对于所有 \(1\le i<j\le n\) ,有 \(\gcd(a_i + x, a_j + x) = 1\) 成立。
\(1\le t\le 100, 2\le n\le 100, 1\le a_i\le 10^{18}, \sum n\le 10^3\)
1S,256MB。

赛时写了个小范围暴力大范围无解的东西企图卡过去真是笑死我了。

首先数列中不能有相同的数。

之后考虑一种显然的特殊情况,当 \(\{a_i\}\) 中有至少两个奇数和两个偶数时,\(x\) 取任意值时数列中都至少有两个偶数,此时无解。

换个角度,上述情况的本质是在 \(\bmod 2\) 意义下考虑了原数列。当数列中 \(0,1\) 都出现了至少两次时无解。
扩展到其他的模数 \(p\),发现也有上述规则成立。即如果原数列 \(\{a_i\}\) 合法,则对于任何质数 \(p\),原数列在 \(\bmod p\) 意义下,\(0\sim p-1\) 的出现次数不都大于等于 \(2\)。否则无论 \(x=k\times p + r (k,r\in \N, 0\le r<p)\) 取何值,总有两个数有共同的公约数 \(p\)

由于 \(n\) 的范围较小,则可通过枚举质数 \(p\) 进行上述检测来判断数列是否合法。由鸽巢原理,当 \(p>\frac{n}{2}\) 时,上述判断结果总是合法的,则仅需枚举 \(2\sim \frac{n}{2}\) 中的质数即可。由素数定理,这样的质数约有 \(\frac{n}{\ln n}\) 个。

总复杂度为 \(O(\frac{t\times n^2}{\ln n})\) 级别。

代码里懒得写判断质数了,复杂度成 \(O(t\times n^3)\) 了,但显然不影响正确性。

//By:Luckyblock
/*
*/
#include <cstdio>
#include <cctype>
#include <algorithm>
const int kN = 110;
#define LL long long
//=============================================================
LL a[kN], num[kN];
//=============================================================
inline LL read() {
	LL f = 1, w = 0; char ch = getchar();
	for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = - 1;
	for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + ch - '0';
	return f * w;
}
LL gcd(LL x_, LL y_) {
  return y_ ? gcd(y_, x_ % y_) : x_;
}
//=============================================================
int main() {
	int T = read();
  while (T --) {
    int n = (int) read();
    for (int i = 1; i <= n; ++ i) a[i] = read();
    
    int flag = 0;
    for (int i = 1; i <= n; ++ i) {
      for (int j = i + 1; j <= n; ++ j) {
        if (a[i] == a[j]) {
          flag = 1;
          break;
        }
      }
    }
    if (flag) {
      printf("NO\n");
      continue;
    }
    
    for (int p = 2; 2 * p <= n; ++ p) {
      flag = 1;
      for (int i = 0; i < p; ++ i) num[i] = 0;
      for (int i = 1; i <= n; ++ i) num[a[i] % p] ++;
      for (int i = 0; i < p; ++ i) flag &= (num[i] >= 2);
      if (flag) break;
    }
    printf("%s\n", flag ? "NO" : "YES");
  }
	return 0;
}
/*
2 3 4 5
3 4 5 6
3 6 9
4 7 10
5 8 11

3 9 11
4 10 12
5 11 13

4 10 14
5 11 15
7 13 17
*/

D

Koxia 和 Mahiru 两个人在玩一个游戏。规则如下:
首先给出三个长度为 \(n\) 的整数列 \(a,b,c\),满足 \(1\le a_i,b_i,c_i\le n\),之后进行 \(n\) 轮游戏。第 \(i\) 轮规则如下:

  • 令可重集合 \(S = \{a_i, b_i, c_i\}\)
  • Koxia 首先可从 \(S\) 中任意删去一个数。
  • Mahiru 再从剩余的元素中任意选择一个作为 \(d_i\)

\(n\) 轮游戏结束后,如果 \(\{d_i\}\) 是一个 \(1\sim n\) 的排列,则 Koxia 胜利,否则 Mahiru 胜利。

现在共有 \(t\) 组数据,每组数据给定两个长度为 \(n\) 的整数列 \(a\)\(b\),满足 \(1\le a_i,b_i\le n\)。求有多少种长度为 \(n\) 的数列 \(c\),满足 \(1\le c_i\le n\),且使得进行上述游戏时 Koxia 必胜。答案对 \(998244353\) 取模。
\(1\le t\le 2\times 10^4, 1\le n\le 10^5, 1\le a_i,b_i\le n, \sum n\le 10^5\)
2S,256MB。

神奇妙妙模型转化题,学到许多。

先考虑 \(a,b,c\) 均确定的情况。手玩几组数据,可以发现如下结论:

  1. 一共只有 \(n\) 轮游戏。如果 Koxia 必胜,则每一轮游戏 Mahiru 被迫选择的数必须不同。
  2. 则易发现,如果在第 \(i\) 轮游戏中,Koxia 删数后剩余的两个数 \(\{x_i, y_i\}\)不同,且为了满足结论 1,其他各轮中 Mahiru 选择的数 \(d_i\) 均不同,由鸽巢原理,在其他 \(n-1\) 轮中至少会出现一次 \(x_i\) 或者 \(y_i\),则此时 Koxia 无法必胜。
  3. 由结论 1、2,则在每一轮游戏中,Koxia 删数后剩余的两个数必须相同,且各轮中剩余的数均不同(构成排列)。
  4. 则剩余的数 \(d_i\) 一定是 \(a_i,b_i\) 中的一个。对于给定的一组数列 \(a,b\),如果 \(a_i\not= b_i\),则有 \(c_i = a_i\)\(c_i = b_i\)。特别地,如果 \(a_i=b_i\),则 \(c_i\) 可取 \(1\sim n\) 的任意值。
  5. 特别的,当无法通过删去 \(a_i,b_i\) 中的任意一个使得剩余的数成为排列时,Koxia 无法必胜。

综上,问题转化为:

  1. 判断能否通过删去 \(a_i,b_i\) 中的任意一个,使得剩余的数成为排列。
  2. 在此基础上判断每个 \(c_i\) 的取值以计算方案数。

考虑建立神奇妙妙图论模型。在 \(a_i\)\(b_i\) 间连接一条无向边,得到一个 \(n\) 个节点 \(n\) 条边,可能有自环的无向图。每条边连接的两个节点的值至多只能选一个,在无向图上考虑,问题转化为:求有多少种为每条边指定方向的方案,使得所有节点的入度均为 1

容易证明,当且仅当每个连通块的无向边数与节点数均相同时,存在对应的方案。
证明充分性:此时每个连通块都是一个基环树。一种构造方法为:先不考虑一条环边,令该环边某端点为根使之成为有根树,令有根树上所有的边都指向深度更深的点,最后将该环边指向根。存在自环时上述构造方案也成立。
证明必要性:所有节点入度均为 1,则边数肯定与节点数两相同。

则可通过 dfs 统计每个连通块的信息非常简单地判断是否有解。解决了问题 1,在此基础上考虑如何计算方案数。

在一个有贡献的图论模型上,对于每一个连通块:

  1. 树边只有一种指定方向的方案。
  2. 对于非自环的环边构成的环,有环绕方向不同的 2 种构造方案,对应着 2 种不同的 \(c\) 的取值方案。
  3. 对于有自环的连通块,在图上仅有一种构造方案,但由结论 4,此时自环的点对应的 \(c_i\)\(n\) 种取值。

统计连通块信息时顺便统计成环情况,将每个连通块的方案数按照乘法法则相乘即得答案。

上述过程看似复杂,但仅需进行一次 \(dfs\) 即可。总复杂度 \(O(tn)\) 级别。

//By:Luckyblock
/*
*/
#include <cstdio>
#include <cctype>
#include <algorithm>
#define LL long long
const int kN = 1e5 + 10;
const int kM = kN << 1;
const LL mod = 998244353;
//=============================================================
int n, a[kN], b[kN];
int edgenum, v[kM], ne[kM], head[kN];
int circle_size, node_num, edge_size, dep[kN];
bool vis[kN];
LL ans;
//=============================================================
inline int read() {
	int f = 1, w = 0; char ch = getchar();
	for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = - 1;
	for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + ch - '0';
	return f * w;
}
void Add(int u_, int v_) {
  v[++ edgenum] = v_;
  ne[edgenum] = head[u_];
  head[u_] = edgenum;
}
void Dfs(int u_, int fa_, int dep_) {
  ++ node_num;
  vis[u_] = true;
  dep[u_] = dep[fa_] + 1;
  for (int i = head[u_]; i; i = ne[i]) {
    ++ edge_size;
    int v_ = v[i];
    if (vis[v_]) {
      if (v_ == u_) circle_size = 1;
      continue;
    }
    Dfs(v_, u_, dep_ + 1);
  }
}
void Init() {
  n = read();
  ans = 1;
  edgenum = 0;
  for (int i = 1; i <= n; ++ i) head[i] = vis[i] = dep[i] = 0;
  
  for (int i = 1; i <= n; ++ i) a[i] = read();
  for (int i = 1; i <= n; ++ i) b[i] = read();
  for (int i = 1; i <= n; ++ i) Add(a[i], b[i]), Add(b[i], a[i]);
}
//=============================================================
int main() {
	int T = read();
  while (T --) {
    Init();
    for (int i = 1; i <= n; ++ i) {
      if (!vis[i]) {
        edge_size = node_num = 0;
        circle_size = 2;
        Dfs(i, 0, 1);
        if (2 * node_num != edge_size) ans = 0;
        ans = 1ll * ans * (circle_size == 1 ? n : 2) % mod;
      }
    }
    printf("%lld\n", ans);
  }
	return 0;
}
/*
3 4
3 5
1 2
3 5
4 5
*/

写在最后

其他题赛时没看,先不补了。

他妈的最近两周阳了以来 krkr 模拟器使用时长达到了惊人的 50 个小时,我是超级 gal 废物

可怜金发小女孩
posted @ 2022-12-31 15:55  Luckyblock  阅读(52)  评论(0编辑  收藏  举报