首页 > 其他分享 >CodeTON Round 8 (Div. 1 + Div. 2, Rated, Prizes!)

CodeTON Round 8 (Div. 1 + Div. 2, Rated, Prizes!)

时间:2024-04-08 11:13:48浏览次数:28  
标签:std Rated int cin long kN Prizes 涂色 Div

目录

写在前面

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

过了这么长时间才来补太唐了、、、

赛时写 D 写了一坨呃呃,用刷表法总是不可避免地要多枚举一个 \(O(n)\) 比较+转移妈的,赛后一看填表法+堆就不用枚举了笑烂了

A

签到。

完全相等的数列随便轮换都是有序的,而不完全相等的有序数列,经过轮换后除非恢复原状一直是无序的。

则当且仅当 \(k=1\) 或 \(k=n\) 时有解。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
//=============================================================
//=============================================================
//=============================================================
int main() {
  //freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  int T; std::cin >> T;
  while (T --) {
    int n, k; std::cin >> n >> k;
    if (k == 1) {
      for (int i = 1; i <= n; ++ i) std::cout << i << " ";
      std::cout << "\n";
    } else if (n == k) {
      for (int i = 1; i <= n; ++ i) std::cout << 1 << " ";
      std::cout << "\n";
    } else {
      std::cout << -1 << "\n";
    }
  }
  return 0;
}

B

简单思维。

考虑在顺序枚举数列 \(a\) 的同时维护当前 \(\operatorname{mex}\) 并构造排列。

由 \(\operatorname{mex}\) 的性质可知,若 \(p_i\not= \operatorname{mex}(p_1, \cdots, p_{i - 1})\) 时,必然有 \(p_i>\operatorname{mex}(p_1, \cdots, p_{i - 1})\) 使得 \(a_i < 0\)。

则对于 \(a_i<0\),加入 \(p_i\) 后 \(\operatorname{mex}\) 不变,可直接计算出 \(p_i= \operatorname{mex} - a_i\);对于 \(a_i>0\) 则一定有 \(p_i = \operatorname{mex}\),此时更新 \(\operatorname{mex}\) 即可。

总时间复杂度 \(O(n)\) 级别。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 2e5 + 10;
//=============================================================
int n, a[kN], p[kN];
int yes[kN];
//=============================================================
//=============================================================
int main() {
  //freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  int T; std::cin >> T;
  while (T --) {
    std::cin >> n;
    for (int i = 1; i <= n; ++ i) std::cin >> a[i], yes[i - 1] = 0;

    int nowmex = 0;
    for (int i = 1; i <= n; ++ i) {
      if (a[i] < 0) {
        p[i] = nowmex - a[i], yes[p[i]] = 1;
      } else {
        yes[nowmex] = 1;
        while (nowmex < n && yes[nowmex]) ++ nowmex;
        p[i] = nowmex - a[i];
      }
    }
    for (int i = 1; i <= n; ++ i) std::cout << p[i] << " ";
    std::cout << "\n";
  }
  return 0;
}

C1

枚举,思维。

首先把 \(x=2\) 的情况特判掉。

手玩下发现对于由被选中的 \(x\) 个点构成的 \(x\) 边形其最多分割出三角形的数量固定为 \(x-2\),再枚举特判被选中的相邻的两个点连线时能否在原图形中多分割出一个三角形(也即是否距离为 2)即可。

需要给点排个序,总时间复杂度 \(O(x\log x)\) 级别。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 2e5 + 10;
//=============================================================
int n, x, y, c[kN];
//=============================================================
//=============================================================
int main() {
  //freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  int T; std::cin >> T;
  while (T --) {
    std::cin >> n >> x >> y;
    if (x == 2) {
      int a, b; std::cin >> a >> b;
      if (a > b) std::swap(a, b);
      if (n == 4 && abs(a - b) == 2) {
        std::cout << 2 << "\n";
      } else if (n > 4 && (b - a == 2 || a + n - b == 2)) {
        std::cout << 1 << "\n";
      } else {
        std::cout << 0 << "\n";
      }
    } else {
      for (int i = 1; i <= x; ++ i) std::cin >> c[i];
      std::sort(c + 1, c + x + 1);
      c[x + 1] = n + c[1];

      int ans = 0;
      for (int i = 2; i <= x + 1; ++ i) {
        if (c[i] - c[i - 1] == 2) ++ ans;
      }
      std::cout << ans + x - 2 << "\n";
    }
  }
  return 0;
}

C2

枚举,思维。

由 C1 的结论可知,每当多加一个被选择的点,则被选择的点构成的多边形边数加 1,则分割出三角形的数量至少增加 1。

那么是否可能增加超过 1 呢?答案是可能的。考虑四个相邻的点 \(A,B,C,D\) 且其中 \(A, D\) 已被选择,则若选择了 \(B\) 则可以额外分割出 \(\triangle BCD\)(等价于也选择了 \(C\))。

于是一种显然的贪心是考虑枚举所有被选择的点对 \(A, B\),考虑在 \(A, B\) 中间所有点中,从 \(A\) 开始以步长为 2 不断地选择未被选择的点;特别地,若 \(A, B\) 距离为奇数,则可以额外分割出一个三角形。

于是考虑将所有相邻两个被选择点之间的距离,按照第一优先级奇距离优先,第二优先级长度递增排序,然后对这些距离按上述思路贪心地加点即可。

总时间复杂度 \(O(x\log x)\) 级别。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 2e5 + 10;
//=============================================================
int n, x, y, c[kN], d[kN];
//=============================================================
bool cmpd(int fir_, int sec_) {
  if (fir_ % 2 != sec_ % 2) return fir_ % 2 < sec_ % 2;
  return fir_ < sec_;
}
//=============================================================
int main() {
  //freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  int T; std::cin >> T;
  while (T --) {
    std::cin >> n >> x >> y;
    for (int i = 1; i <= x; ++ i) std::cin >> c[i];
    std::sort(c + 1, c + x + 1);
    c[x + 1] = n + c[1];
    for (int i = 1; i <= x; ++ i) d[i] = c[i + 1] - c[i];
    std::sort(d + 1, d + x + 1, cmpd);

    int ans = 0, delta = y, added = 0;
    for (int i = 1; i <= x; ++ i) {
      if (d[i] == 2) ++ ans;
      else {
        int temp = d[i], need = (temp - 1) / 2;
        temp %= 2;
        if (need <= delta) delta -= need, ans += need, added += need;
        else ans += delta, added += delta, temp = kN, delta = 0;
        if (temp == 0) ++ ans;
      }
    }
    std::cout << ans + x + added - 2 << "\n";
  }
  return 0;
}

D

DP?

考虑仅求最大值的过程,发现每次涂色仅与上一次被涂色的位置有关,感觉很可 DP 的样子,考虑记状态 \(f_{i}(-1\le i\le n)\) 表示使用前 \(i\) 个位置进行涂色且第 \(i\) 个位置被占用(可能被涂色或未被涂色),可以达到的最大权值,初始化 \(f_{-1} = f_{0} = 0\),则有转移:

\[\begin{aligned} \forall 1\le i\le n,\ f_{i}\leftarrow \begin{cases} f_{i - 1}\\ \max\limits_{j\le i - 2} \left(f_{j} + a_{j+2, i}\right) \end{cases} \end{aligned}\]

答案即为 \(f_n\)。

现要求前 \(k\) 大值,看到这个 DP 转移顺序有一种拓扑序上 \(k\) 短路的美感,显然想到在转移过程中仅有每个节点的前 \(k\) 短路会对最终的 \(k\) 短路有贡献。

考虑修改状态定义,记 \(f_i(-1\le i\le n)\) 表示表示使用前 \(i\) 个位置进行涂色且第 \(i\) 个位置被占用(可能被涂色或未被涂色),可以达到的前 \(k\) 大的权值的集合。初始化 \(f_{-1} = f_{0} = \{0\}\),转移时考虑维护一个大小为 \(i+1\) 的堆,将 \(-1\sim i-1\) 中的最大值转移后对 \(f_i\) 的贡献加入堆中,然后不断取出堆中的最大值,每次取出都将对应位置的集合中次大值转移后对 \(f_i\) 的贡献加入堆中。

答案即为 \(f_n\) 中的最大值。

发现每个状态中仅有 \(k\) 个值,每次转移都需要维护一个大小为 \(O(n)\) 级别的堆,且仅会进行 \(O(k)\) 次插入查询删除操作,则总时间复杂度 \(O(nk\log n)\) 级别。

实现时用了迭代器,太好用啦 STL!

//DP?
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
#define pLi std::pair<LL,int>
#define mp std::make_pair
const int kN = 1e3 + 10;
const int kd = 1;
//=============================================================
int n, k, a[kN][kN];
std::vector <LL> f[kN];
std::vector <LL>::iterator it[kN];
//=============================================================
void Init() {
  std::cin >> n >> k;
  for (int i = 1; i <= n; ++ i) {
    for (int j = i; j <= n; ++ j) {
      std::cin >> a[i][j];
    }
  }
}
void Solve() {
  for (int i = -1; i <= n + 1; ++ i) f[i + kd].clear();
  f[-1 + kd].push_back(0);
  f[0 + kd].push_back(0);

  for (int i = 1; i <= n; ++ i) {
    std::priority_queue <pLi> q;
    for (int j = -1; j <= i - 1; ++ j) {
      it[j + kd] = f[j + kd].begin();
      q.push(mp(*it[j + kd] + (j != i - 1) * a[j + 2][i], j));
    }
    
    int cnt = k;
    while (!q.empty() && cnt) {
      LL v = q.top().first;
      int p = q.top().second; q.pop();
      f[i + kd].push_back(v);
      -- cnt, ++ it[p + kd];
      if (it[p + kd] == f[p + kd].end()) continue;

      q.push(mp(*it[p + kd] + (p != i - 1) * a[p + 2][i], p));
    }
  }
}
//=============================================================
int main() {
  // freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  int T; std::cin >> T;
  while (T --) {
    Init();
    Solve();
    for (auto x: f[n + kd]) std::cout << x << " ";
    std::cout << "\n";
  }
  return 0;
}

E

咕咕咕~

写在最后

学到了什么:

  • D:填表法!

标签:std,Rated,int,cin,long,kN,Prizes,涂色,Div
From: https://www.cnblogs.com/luckyblock/p/18120703

相关文章

  • 增强检索问答RAG研究成果综述 Retrieval-Augmented Generation for AI-Generated Cont
    文章目录引言背景贡献*相关工作**路线图*初步*概述**生成器*Transformer模型LSTMDiffusion模型***GAN****检索器*稀疏检索*:*密集检索*:****其他方法**:*方法*RAG基础*基于查询的RAG(Query-basedRAG)*:****基于潜在表示的RAG**(LatentRepresentation-basedRA......
  • 4.5Codeforces Round 905 (Div. 3)
    C题题意:几个数字,挑选其中几个进行+1.得到的数字的乘积可以整除k注意题目条件:k只能是2,3,4,5这几种情况每个数字只能是1——10(不算大)(好像没啥用,因为可以自增超过10)思路:对于2,3,5要想整除,这些个数里必须要有一个数是可以整除2,3,5的。所以思路很简单,去造,找到一个“变成5的倍数”所需......
  • An Efficient Approach for Cross-Silo Federated Learning to Rank文章翻译
    AnEfficientApproachforCross-SiloFederatedLearningtoRank一种有效的cross-silo(跨孤岛)联邦排名学习方法摘要传统的排名学习(LTR)模型通常采用基于大量数据的集中式方法进行训练。然而,随着人们数据隐私意识的提高,像以前一样从多个所有者收集数据变得更加困难,由此......
  • Educational Codeforces Round 157 (Rated for Div. 2) —— C题
    EducationalCodeforcesRound157(RatedforDiv.2)C.TornLuckyTicket一道经典的前缀哈希题先看代码stra[N];voidmoon(){cin>>n;eps(i,1,n)cin>>a[i];//奇数+奇数偶数+偶数llres=0;map<pll,ll>p;map<ll,ll>pp;eps(i,1,n){res=0;for......
  • Codeforces Round 937 (Div. 4)
    CodeforcesRound937(Div.4)B题是输出规律图形题,对于这种题不能直接不思考就上去模拟,而应该思考一下数学规律,往往是模意义下的规律。本题只需要模4以后的结果分为两类,分别讨论即可。对于模4可以利用位运算取出第二位的,这与模2同理。chars1='#';chars2='.';voidsolve(){......
  • Codeforces Round 937 (Div. 4) D题(无脑做法)
    D.ProductofBinaryDecimals题目:提示:首先如果该数目都是1和0组成那肯定输出yes了,还有这个数如果是二进制的乘积也可以yes现在举个例子看看121=11x1114641=11x11x11x11显然也是yes,但是要如何做呢,下面介绍无脑做法。AC代码#include<bits/stdc++.h>usingnamespace......
  • Codeforces Round 901 (Div. 2) E
    链接有些部分和常规的题目有很大的区别,所以我理解的过程产生的很大很大的障碍。我看了4天吧,这题和题解。好烦。我的第一个思路就是暴力。因为很明显,其实对于每一个二进制位,a,b,m的情况数量是很有限的,就只有8种,而相应的,c,d的对应位是由这4种位运算得到的。我先尝试对每一种情况看......
  • Codeforces Round 918 (Div. 4)
    CodeforcesRound918(Div.4)D:本题从实现上来说正难则反,应该倒着做在我正着做的时候,由于在访问后面元素的时候没有判边界,导致数组越界,出现奇怪字符在最后答案中。intn,m;inta[N];boolcheck(charc){ if(c=='a'||c=='e')returntrue; elsereturnfalse;}voidsolv......
  • 状压dp板子(cf div4 #937)
    #include<bits/stdc++.h>usingnamespacestd;intn;vector<int>v[20];stringa[20],b[20];booldp[500010][20];voiddfs(ints,intnow){dp[s][now]=true;for(autonxt:v[now]){if(s&(1<<nxt))continue;......
  • WolfInZooDivOne
    dp#预处理\(dp_{i,j}\)表示第\(i\)个选择,\(i\)前面的第一个为\(j\)的方案数预处理不合法的区间,暴力转移//Author:xiaruize#ifndefONLINE_JUDGEboolstart_of_memory_use;#endif#include<bits/stdc++.h>usingnamespacestd;#ifndefONLINE_JUDGEclock_tstar......