首页 > 其他分享 >Codeforces Round 897 (Div. 2)

Codeforces Round 897 (Div. 2)

时间:2023-09-13 10:36:52浏览次数:38  
标签:ch 897 int Codeforces long kN isdigit Div getchar

目录

写在前面

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

简略题解。

还好没掉分。

A

令原数列中第 \(k\) 大对应 \(k\) 即可。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 4e4 + 10;
//=============================================================
int n, num, b[kN];
struct Data {
  int a, pos;
} a[kN];
//=============================================================
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;
}
bool cmp(Data fir_, Data sec_) {
  return fir_.a > sec_.a;
}
//=============================================================
int main() {
  // freopen("1.txt", "r", stdin);
  int T = read();
  while (T --) {
    n = read();
    for (int i = 1;i <= n; ++ i) a[i] = (Data) {read(), i};
    std::sort(a + 1, a + n + 1, cmp);
    for (int i = 1; i <= n; ++ i) b[a[i].pos] = i;
    for (int i = 1; i <= n; ++ i) printf("%d ", b[i]);
    printf("\n"); 
  }
  return 0;
}

B

考虑给定串前后的对应部分原来是否相同,若不同则需要且仅需要在这两个位置中改一个,若相同则可以都不改或者都改。特别地,若 \(n\) 为奇数则中间位置改不改都行。

于是分别记录两种位置的数量 \(c_0, c_1\),显然 \(t_{c_0 + 2\times k} (0\le k\le c_1)=1\)。若原串位置为奇数则额外有 \(t_{c_0 + 2\times k + 1} = 1\)。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 1e5 + 10;
//=============================================================
int n, flag1, cnt0, cnt1;
char s[kN];
bool ans[kN];
//=============================================================
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() {
  // freopen("1.txt", "r", stdin);
  int T = read();
  while (T --) {
    n = read(); scanf("%s", s + 1);
    flag1 = n % 2, cnt0 = cnt1 = 0;
    for (int i = 1, j = n; i < j; ++ i, -- j) {
      if (s[i] == s[j]) ++ cnt0;
      else ++ cnt1;
    }
    for (int i = 0; i <= n; ++ i) ans[i] = 0;
    if (flag1) {
      for (int i = cnt1, j = 0; j <= cnt0; i += 2, ++ j) ans[i] = ans[i + 1] = 1;
    } else {
      for (int i = cnt1, j = 0; j <= cnt0; i += 2, ++ j) ans[i] = 1;
    }
    for (int i = 0; i <= n; ++ i) printf("%d", ans[i] ? 1 : 0);
    printf("\n");
  }
  return 0;
}
/*
101 011

1001 0 0011
2
2

1 0 0
1

*/

C

傻逼交互、、、看到交互就先跑了亏死。

CF 的交互很亲民,望周知。

第一次加 \(\operatorname{mex}\),之后删什么加什么。

正确性显然。

//By:Luckyblock
/*
*/
#include <cstdio>
#include <cctype>
#include <algorithm>
const int kN = 1e5 + 10;
//=============================================================
int n, mex, a[kN];
//=============================================================
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() {
  // freopen("1.txt", "r", stdin);
  int T = read();
  while (T --) {
    n = read();
    mex = 0;
    for (int i = 1; i <= n; ++ i) {
      a[i] = read();
      if (a[i] == mex) ++ mex;
    }

    for (int cnt = 1, del; ; ++ cnt) {
      if (cnt % 2 == 1) {
        if (cnt == 1) {
          printf("%d\n", mex);
          fflush(stdout);
          ++ mex;
          for (int i = mex; i <= n; ++ i) if (a[i] == mex) ++ mex;
        } else {
          printf("%d\n", del);
          fflush(stdout);
        }
      } else {
        del = read();
        if (del == -1) break;
        if (del == -2) return 0;
      }
    }
  }
  return 0;
}

D

套路。

先特判 \(k=1\),此时当且仅当 \(b_i=i\) 有解;若 \(k\not= 1\),则当 \(b_i=i\) 时肯定无解。

手玩一下可以发现,若对于位置 \(\{p_1, p_2, \dots, p_k\}\) 满足 \(b_{p_1} = p_2, b_{p_2} = p_3, \dots, b_{p_k} = p_1\),那么进行一次 \(l = \{p_1, p_2, \dots, p_k\}\) 的操作即可将这些位置全部修改成目标。

发现上面的情况类似于构成了一个大小为 \(k\) 的环,转换为图论模型,从节点 \(i\) 向 \(a_i\) 连边,则没有零出度的点,构成了一片基环内向森林。

显然,若其中的所有基环内向树都是大小为 \(k\) 的环构成时皆大欢喜,分别对环中的节点代表的位置进行一次操作即可;否则若所有基环内向树中仅有大小为 \(k\) 的环时,可以考虑按照拓扑序先对链上的节点代表的位置进行操作,最后再对环中的节点代表的位置进行一次操作即可。通过上面的操作方案可以推出若出现大小不为 \(k\) 的环时无解。

于是仅需 Tarjan 检查原图中的所有环大小是否为 \(k\) 即可。总时间复杂度 \(O(n)\) 级别。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 1e6 + 10;
//=============================================================
int n, m, k, a[kN];
int edgenum, head[kN], v[kN << 1], ne[kN << 1];
int dfnnum, belnum, dfn[kN], low[kN], bel[kN], sz[kN];
std::stack <int> st;
//=============================================================
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 Tarjan(int u_) {
  low[u_] = dfn[u_] = ++ dfnnum;
  st.push(u_);
  for (int i = head[u_]; i; i = ne[i]) {
    int v_ = v[i];
    if (!dfn[v_]) {
      Tarjan(v_);
      low[u_] = std::min(low[u_], low[v_]);
    } else if (!bel[v_]) {
      low[u_] = std::min(low[u_], dfn[v_]);
    }
  }
  if (low[u_] == dfn[u_]) {
    ++ belnum;
    for (int now = 0; now != u_; st.pop()) {
      now = st.top();
      bel[now] = belnum;
      ++ sz[belnum];
    }
  }
}
void Init() {
  n = read(), k = read();
  edgenum = dfnnum = belnum = 0;
  while (!st.empty()) st.pop();
  for (int i = 1; i <= n; ++ i) {
    head[i] = dfn[i] = low[i] = bel[i] = sz[i] = 0;
  }
  for (int i = 1; i <= n; ++ i) a[i] = read(), Add(i, a[i]);
}
//=============================================================
int main() {
  // freopen("1.txt", "r", stdin);
  int T = read();
  while (T --) {
    Init();
    int flag = 1;
    if (k == 1) {
      for (int i = 1; i <= n; ++ i) if (a[i] != i) flag = 0;
      printf("%s\n", flag ? "YES" : "NO");
      continue;
    } else {
      for (int i = 1; i <= n; ++ i) if (a[i] == i) flag = 0;
      if (!flag) {
        printf("NO\n");
        continue;
      }
    }

    for (int i = 1; i <= n; ++ i) if (!dfn[i]) Tarjan(i);
    for (int i = 1; i <= belnum; ++ i) {
      if (sz[i] > 1 && sz[i] != k) {
        flag = 0;
        break;
      }
    }
    printf("%s\n", flag ? "YES" : "NO");
  }
  return 0;
}

E1/E2

傻逼交互、、、

写完 D 就下班了亏死,要是把 E 写了就飞升了。

钦定了 \(n,k\) 均为偶数,且 \(k\le n\le k^2\),且有 \(k^2\le 2500\),显然进行不多于 \(k\) 次操作就可以覆盖整个数列。

若 \(k\mid n\) 皆大欢喜,进行 \(\frac{n}{k}\) 次操作恰好覆盖整个数列即可,否则考虑如何构造出最后的长度为 \(n \bmod k\) 的不完整段的异或和。

首先想到必须对 \([n - k + 1, n]\) 进行一次操作来得到这段的异或和,然后考虑通过异或去除重复部分的贡献。由于有进行一次操作后被操作的序列翻转的性质,一个显然的想法是在对 \([n - k + 1, n]\) 进行操作前先对它之前的某一段进行操作,在获得了一部分信息的同时,将重复部分翻转到 \([n - k + 1, n]\) 中,再对它进行操作来获得全部的信息。

设 \(s = k\times \left\lfloor\frac{n}{k}\right\rfloor + 1\),即最后不完整段的第一个位置,钦定了 \(n, k\) 为偶数,手玩一下可以发现先对 \(\left[\left\lfloor\frac{n+s}{2}\right\rfloor - k + 1, \left\lfloor\frac{n+s}{2}\right\rfloor\right]\) 进行一次操作,再对 \([n - k + 1, n]\) 进行一次操作,两次操作的结果的异或即为最后不完整段的异或和。

上述过程仅需 \(k+2\le 52\) 次操作,稳过。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
//=============================================================
int n, k;
//=============================================================
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 Query(int x_) {
  printf("? %d\n", x_);
  fflush(stdout);
  return read();
}
//=============================================================
int main() {
  // freopen("1.txt", "r", stdin);
  int T = read();
  while (T --) {
    n = read(), k = read();
    int i = 1, ans = 0;
    for (i = 1; i + k - 1 <= n; i += k) {
      ans ^= Query(i);
    }
    if (i <= n) {
      ans ^= Query((i + n) / 2 - k + 1);
      ans ^= Query(n - k + 1);
    }
    printf("! %d\n", ans);
    fflush(stdout);
  }
  return 0;
}

F

写在最后

  • 如果有轮换的性质可以考虑套路地建立图论模型。
  • CF 的交互题很亲密,望周知。

标签:ch,897,int,Codeforces,long,kN,isdigit,Div,getchar
From: https://www.cnblogs.com/luckyblock/p/17698839.html

相关文章

  • 【题解】Educational Codeforces Round 141(CF1783)
    评价:educationalA.MakeitBeautiful题目描述:如果一个数组中存在一个数恰好等于该数前面所有数之和,那么这个数组就是丑的。如果一个数组不是丑的,就是美的。比如说:数组$[6,3,9,6]$是丑的,因为\(9=6+3\);数组$[5,5,7]$是丑的,因为第二个\(5=5\)。数组$......
  • Codeforces Round 897 (Div. 2)
    F.MostDifferentTree当\(n=2\)时,只能构造一条长度为\(2\)的链。当\(n\ge3\)时,对于\(i\)\((1\lei\len)\),以\(i\)作为根的树记为\(h_i\),考虑枚举树找一个大小为\(s\)的树\(t\),使得不存在任何一个\(h_i=t\),且\(s\)尽可能小,然后从\(1\)连一条链到该数的根......
  • html div && span 容器元素
    htmldiv&&span容器元素div标签定义HTML文档中的一个分隔区块或者一个区域部分,标签常用于组合块级元素,以便通过CSS来对这些元素进行格式化span用于对文档中的行内元素进行组合标签提供了一种将文本的一部分或者文档的一部分独立出来的方式<html><head>......
  • Codeforces Round 897 (Div. 2)
    CodeforcesRound897(Div.2)A.green_gold_dog,arrayandpermutation分析:由题意:\[c_i=a_i-b_i\]\(c_i\)种类最多就是\(n\)个数都不同。若\(a_i\)不断变大,\(b_i\)不断变小,那么\(c_i\)会不断变大。代码:#include<bits/stdc++.h>usingnamespacestd;usingll......
  • Codeforces Round 897 (Div. 2) A~E
    CodeforcesRound897(Div.2)A~EA:原先数组里面最小的位置放最大的数,次小的放次大的即可。voidsolve(){ intn;cin>>n; for(inti=1;i<=n;i++){ intx;cin>>x; c[i]={x,i}; } sort(c+1,c+1+n); intnum=n; for(inti=1;i<=n;i++){ ans[c[i].second]=num;num--......
  • Codeforces Round 896 (Div. 2)
    CodeforcesRound896(Div.2)A.MakeItZero代码:#include<bits/stdc++.h>usingnamespacestd;usingll=longlong;usingi128=__int128;intn,m;voidsolve(){scanf("%d",&n);vector<int>a(n+1);for(inti......
  • CodeForces 542B Duck Hunt
    洛谷传送门CF传送门首先转化一下,让鸭子不动,猎人往右移动,就相当于开的相邻两枪距离\(>m\)。设\(f_{x,i}\)为仅考虑\(r\lex\)的鸭子,上一次在\(i\)开枪,能打到的最大鸭子个数。\(f_{x-1}\tof_x\)时,首先有\(f_{x,i}=f_{x-1,i}\)。我们先找到所有\(r=x\)......
  • Codeforces Round 896 (Div. 1)
    Preface不管怎么说,最后还是被我苟上橙名了(虽然刚好2100整,不多不少)感觉我在1900~2100之间卡了好久好久,反观我的队友都是打上紫名后随便两三场就打上橙了,狠狠地羞辱我这个铁混子由于暑假集训打的校内排名比较高,作为新队伍也拿到了今年的一场CCPC+一场ICPC的名额,虽然要自费出行但......
  • Codeforces Round 101 (Div. 2) C - E
    C.Queue(思维、排序、构造、*1800)题意:$n$个人排队,为他们构造一组身高,使得$x$的前面有$a_i$个人比他高。如果无法构造满足所有条件的身高序列,输出-1。思路:首先考虑,对于$a_i$较大的人,肯定尽可能地将其往队伍后面放,然后从后往前构造,因为只有$......
  • abc288F - Integer Division
    F-IntegerDivision挺有意思的一道题,贪心的做法就是排序之后,逐个加入,如果不能被之前的表示则加入题解证明的话大概是这样考虑第i个数选不选首先加入前面选的数,如果能够表示当前的数,则必然不选否则前面的数不能表示当前的数,假如我们不选\(p_i\)假设最后得到一个合法序列,则......