传送门

A. Paint the Numbers

签到。

Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 105;
int n;
int a[N];
bool used[N];
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
sort(a + 1, a + n + 1);
int ans = 0;
for(int i = 1; i <= n; i++) {
if(used[i]) continue;
++ans;
for(int j = i; j <= n; j++) {
if(a[j] % a[i] == 0) used[j] = 1;
}
}
cout << ans;
return 0;
}

B. Koala and Lights

由于数据范围很小,暴力枚举即可。

Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 105; int n;
int a[N], b[N];
char s[N]; int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n;
cin >> s + 1;
for(int i = 1; i <= n; i++) cin >> a[i] >> b[i];
int ans = 0;
for(int i = 1; i <= n; i++) {
if(s[i] == '1') ++ans;
}
for(int i = 1; i <= 5000; i++) {
int tmp = 0;
for(int j = 1; j <= n; j++) {
if(i - b[j] < 0) continue;
int now = i - b[j];
if(now % a[j] == 0) {
if(s[j] == '1') s[j] = '0';
else if(s[j] == '0') {
s[j] = '1';
}
}
}
for(int j = 1; j <= n; j++) {
if(s[j] == '1') ++tmp;
}
// if(i < 10) cout << tmp << '\n';
ans = max(ans, tmp);
}
cout << ans;
return 0;
}

C. Paint the Digits

题意:

给出一串数字,现在要给这串数字涂上两种颜色\(1,2\),要求涂色过后从前往后将\(1\)排开,再将\(2\)排开,最终得到一个非递减序列。

思路:

首先序列自动机预处理下一位,然后贪心处理即可。

感性想一下很容易知道染色方案,对于当前位,\(1\)的颜色肯定是下一个最小的值,如果不是则不满足条件;\(1\)染完色过后按同样的方法对\(2\)进行染色,但是起点不同,注意处理一下。

还有一个细节:\(1\)染的颜色的最大值不能超过前面没染颜色的最小值,否则也不满足条件。

Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5; int T, n;
char s[N];
int nxt[N][26];
int last[26];
int col[N]; int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> T;
while(T--) {
cin >> n;
cin >> s + 1;
for(int i = 1; i <= n; i++) col[i] = 0;
for(int i = 0; i < 26; i++) last[i] = n + 1;
for(int i = n; i >= 0; i--) {
for(int j = 0; j < 26; j++) nxt[i][j] = last[j];
if(i) last[s[i] - '0'] = i;
}
int start = 0, up = 26;
for(int i = 0, k; i <= n; i = k) {
int jump = 0;
int low = (i == 0 ? 0 : s[i] - '0');
for(int j = low; j < up; j++) {
if(nxt[i][j] <= n) {
k = nxt[i][j];
jump = 1;
break;
}
}
if(jump == 0) break;
col[k] = 1;
start = s[k] - '0';
if(k != i + 1 && up == 26) {
up = s[i + 1] - '0' + 1;
}
}
for(int i = 0, k; i <= n; i = k) {
int jump = 0;
int low = (i == 0 ? start : s[i] - '0');
for(int j = low; j < 26; j++) {
if(nxt[i][j] <= n && !col[nxt[i][j]]) {
k = nxt[i][j];
jump = 1;
break;
}
}
if(!jump) break;
col[k] = 2;
}
int ok = 1;
for(int i = 1; i <= n; i++) {
if(!col[i]) ok = 0;
}
if(!ok) cout << '-' << '\n';
else {
for(int i = 1; i <= n; i++) cout << col[i];
cout << '\n';
}
}
return 0;
}

D. Cow and Snacks

全局视野来看,并查集搞搞就行,答案就与生成树有关。

Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5; int n, k;
int a[N], b[N];
int f[N], sz[N]; int find(int x) {
return f[x] == x ? f[x] : f[x] = find(f[x]);
} bool Union(int x, int y) {
int fx = find(x), fy = find(y);
if(fx != fy) {
sz[fy] += sz[fx];
f[fx] = fy;
return true;
}
return false;
} int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n >> k;
for(int i = 1; i <= k; i++) {
cin >> a[i] >> b[i];
}
for(int i = 1; i <= n; i++) f[i] = i, sz[i] = 1;
int ans = 0;
for(int i = 1; i <= k; i++) {
if(!Union(a[i], b[i])) ++ans;
}
// int cnt = 0;
// for(int i = 1; i <= n; i++) {
// if(find(i) == i) {
// cnt += sz[i] - 1;
// cout << sz[i] << '\n';
// }
// }
// int ans = n - cnt;
cout << ans;
return 0;
}

E. Rotate Columns

题意:

给出一个\(n*m\)的矩形,满足\(n\leq 12,m\leq 2000\),现在你可以对任意一列执行任意次滑动操作。

记\(r_i\)为第\(i\)行的最大值,求\(\sum_{i=1}^nr_i\)最大为多少。

思路:

一开始看作行也可以滑动,然后就写了一个假题= =

  • 有一个很重要的观察,就是最后的最大值只与最大值最大的\(n\)列有关。
  • 为什么?
  • 假设现在第\(i\)列的最大值为第\(n+1\)大,那么在最优方案中,它肯定不能成为最大值,因为总会存在一列\(j\)可以令其滑动到\(i\)的位置并且其最大值大于\(j\)列。
  • 那么我们将最大的\(n\)列拿出来随机就行了。
  • 因为数据很小,所以可以考虑状压。
  • 枚举状态\(s\),表示在之前的\(i-1\)列中选取某些行作为最大值,和的最大值。之后会新加进来第\(i\)列,显然,第\(i\)列行的状态只能为\(((1<<n)-1)\ xor\ s\)的子集。之后枚举循环位移更新即可。
  • 直接枚举循环位移时间复杂度可能会多处一个\(O(n)\),那么可以将这部分预处理一下。

一开始我卡在枚举循环位移这里,后面想了下,只有枚举循环位移,才会覆盖到所有情况。

Code
#include <bits/stdc++.h>
#define MP make_pair
#define INF 0x3f3f3f3f
#define fi first
#define se second
#define sz(x) (int)(x).size()
//#define Local
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 12, M = 2000; int n, m;
int a[N][M];
pii b[M]; void run() {
cin >> n >> m;
vector <int> col(m);
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> a[i][j];
col[j] = max(col[j], a[i][j]);
}
}
for (int i = 0; i < m; i++) b[i] = MP(col[i], i);
sort(b, b + m); reverse(b, b + m);
m = min(m, n);
int lim = 1 << n;
vector <vector<int>> w(m, vector<int>(lim));
for (int i = 0; i < m; i++) {
int j = b[i].se;
for (int s = 0; s < lim; s++) {
for (int k = 0; k < n; k++) {
int sum = 0;
for (int p = 0; p < n; p++) {
if (s >> ((p + k) % n) & 1) {
sum += a[p][j];
}
}
w[i][s] = max(w[i][s], sum);
}
}
}
vector <int> dp(lim);
for (int i = 0; i < m; i++) {
vector <int> new_dp(lim);
for (int s = 0; s < lim; s++) {
int other = (lim - 1) ^ s;
for (int sub = other; ; sub = (sub - 1) & other) {
int Max = w[i][sub];
new_dp[s ^ sub] = max(new_dp[s ^ sub], dp[s] + Max);
if (sub == 0) break;
}
}
swap(dp, new_dp);
}
cout << dp[lim - 1] << '\n';
} int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
#ifdef Local
freopen("../input.in", "r", stdin);
freopen("../output.out", "w", stdout);
#endif
int t; cin >> t;
while(t--) run();
return 0;
}

F. Koala and Notebook

题意:

给出一张\(n\)个点\(m\)条边的无向图,每条边的编号依次为\(1,2,\cdots,m\)。

现在从\(1\)号结点出发,每经过一条边,则在目前答案后面连上当前边的编号。

比如\(1->2\),编号为\(10\),到达\(2\)结点的结果就为\(10\);之后\(2->3\)的编号为\(11\),那么结果就为\(1011\)。

现在要求到达每个节点的最小答案,由于这个答案可能很大,所以输出对\(1e9+7\)取模的答案。

思路:

一开始想不是很好想,因为思考起来还是挺麻烦的,比较大小则要考虑很多东西。

但其实细化一下思路就能清晰一点:

  • 一般比较字典序大小,第一看长度,第二看不同位的大小关系。
  • 但这里长度不是很好比较,不同编号可能有不同的长度。怎么处理?
  • 拆边就行!将编号拆成多个一位,这样长度就很好考虑。
  • 接下来考虑大小关系。
  • 因为我们从\(1\)出发,所以可以跑个\(bfs\),每次往小的边优先走,那么既能保证长度最小,也能保证值最小了。

大概思路就是这样,关键点就是拆边。

但代码实现还有一点细节:我们\(bfs\)时用\(vector\)来模拟队列,之后再将距离拆细一点(即并不是距离离起点相同的点都拿出来更新),这样就能保证每次更新得到的都是最小答案。不然对于\(0\)通过\(1\)去更新其它点,还不如\(1\)通过\(0\)去更新其它点优,就有问题。

说这么多废话,代码看起来还是比较好懂:

Code
#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
//#define Local
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e6 + 5, MOD = 1e9 + 7; int n, m;
vector <int> g[N][10];
bool chk[N];
int ans[N]; void run() {
int np = n;
for(int i = 1; i <= m; i++) {
int u, v; cin >> u >> v;
int t = i;
vector <int> e;
while(t) {
e.push_back(t % 10);
t /= 10;
}
reverse(all(e));
int pre = u;
for(int j = 0; j < sz(e); j++) {
int to = (j == sz(e) - 1 ? v : ++np);
g[pre][e[j]].push_back(to);
pre = to;
}
pre = v;
for(int j = 0; j < sz(e); j++) {
int to = (j == sz(e) - 1 ? u : ++np);
g[pre][e[j]].push_back(to);
pre = to;
}
}
vector <vector<int>> q(np + 1);
chk[1] = 1; q[0].push_back(1);
int T = 0;
for(int i = 0; i <= T; i++) {
for(int j = 0; j < 10; j++) {
int f = 0;
for(auto x : q[i]) {
for(auto it : g[x][j]) {
if(!chk[it]) {
chk[it] = 1; f = 1;
ans[it] = (1ll * 10 * ans[x] % MOD + j) % MOD;
q[T + 1].push_back(it);
}
}
}
if(f) ++T;
}
}
for(int i = 2; i <= n; i++) cout << ans[i] << '\n';
} int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
#ifdef Local
freopen("../input.in", "r", stdin);
freopen("../output.out", "w", stdout);
#endif
while(cin >> n >> m) run();
return 0;
}

G1. Into Blocks (easy version)

题意:

给出一个长度为\(n,n\leq 2e5\)的序列。

现在可以执行操作:将全部的\(x\)变为\(y\)。

现在问最少多少次操作,使得所有值相同的元素都在同一块中。

思路:

  • 考虑最终状态,一定为多个整块,并且在一个整块中,一定是多个颜色都变为同一颜色。
  • 那么对于\(1\)位置的颜色,一定最后也在一块中,并且目前块结尾为\(last[a_1]\);同时,中间的所有元素都会变为同一颜色,那么我们直接扫过去,因为可能\(last[a_i]>last[a_1]\),我们直接更新右边界即可。
  • 最后我们划分出了多个大区间,在每个区间中贪心考虑保留个数最多的颜色即可。那么我们划分时用一个桶维护一下权值数量即可。

详见代码:

Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 200005; int n, q;
int a[N];
int fir[N], last[N];
int cnt[N]; int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n >> q;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++) {
if(fir[a[i]] == 0) fir[a[i]] = i;
}
for(int i = n; i >= 1; i--) {
if(last[a[i]] == 0) last[a[i]] = i;
}
int ans = 0;
for(int i = 1, j; i <= n; i = j + 1) {
j = last[a[i]];
int st = i;
while(i < j) {
++i; j = max(last[a[i]], j);
}
int tmp = 0;
for(int k = st; k <= j; k++) {
if(++cnt[a[k]] > tmp) tmp = cnt[a[k]];
}
ans += j - st + 1 - tmp;
}
cout << ans;
return 0;
}

Codeforces Round #584的更多相关文章

  1. Codeforces Round #584 E2. Rotate Columns (hard version)

    链接: https://codeforces.com/contest/1209/problem/E2 题意: This is a harder version of the problem. The ...

  2. Codeforces Round #584 D. Cow and Snacks

    链接: https://codeforces.com/contest/1209/problem/D 题意: The legendary Farmer John is throwing a huge p ...

  3. Codeforces Round #584 C. Paint the Digits

    链接: https://codeforces.com/contest/1209/problem/C 题意: You are given a sequence of n digits d1d2-dn. ...

  4. Codeforces Round #584 B. Koala and Lights

    链接: https://codeforces.com/contest/1209/problem/B 题意: It is a holiday season, and Koala is decoratin ...

  5. Codeforces Round #584 A. Paint the Numbers

    链接: https://codeforces.com/contest/1209/problem/A 题意: You are given a sequence of integers a1,a2,-,a ...

  6. Codeforces Round 584 题解

    -- A,B 先秒切,C 是个毒瘤细节题,浪费了很多时间后终于过了. D 本来是个 sb 题,然而还是想了很久,不过幸好没什么大事. E1,看了一会就会了,然而被细节坑死,好久才过. 感觉 E2 很可 ...

  7. Codeforces Round #584 (Div. 1 + Div. 2)

    Contest Page A sol 每次选最小的,然后把它的所有倍数都删掉. #include<bits/stdc++.h> using namespace std; int read( ...

  8. 状压DP--Rotate Columns (hard version)-- Codeforces Round #584 - Dasha Code Championship - Elimination Round (rated, open for everyone, Div. 1 + Div. 2)

    题意:https://codeforc.es/problemset/problem/1209/E2 给你一个n(1-12)行m(1-2000)列的矩阵,每一列都可以上下循环移动(类似密码锁). 问你移 ...

  9. Cow and Snacks(吃点心--图论转换) Codeforces Round #584 - Dasha Code Championship - Elimination Round (rated, open for everyone, Div. 1 + Div. 2)

    题意:https://codeforc.es/contest/1209/problem/D 有n个点心,有k个人,每个人都有喜欢的两个点心,现在给他们排个队,一个一个吃,每个人只要有自己喜欢的点心就会 ...

随机推荐

  1. VisualStudio编译不生成xml、pdb文件的方法

    我们为了减少发布/Release时项目的体积,希望在编译时不生成xml注释文档(包括引用的其他类库),和pdb调试文件 用你喜欢的文本编辑器打开项目.csproj文件,找到PropertyGroup节 ...

  2. Dotnet Core中使用AutoMapper

    官网:http://automapper.org/ 文档:https://automapper.readthedocs.io/en/latest/index.html GitHub:https://g ...

  3. Vue和React的区别,以及如何选择?

    简介 React:React是一个用于创建可重用且有吸引力的UI组件的库.它非常适合代表经常变化的数据的组件. Vue:Vue.js是一个开源JavaScript框架,能够开发单页面应用程序.它还可以 ...

  4. python中 遇到的读取坑2.7和3.6版本的问题

    2.7读取,需要使用io.open 3.x使用open 使用io.open的时候路径需要使用\\ 目前io.open的文件名不能为中文

  5. SQL Server解惑——为什么你的查询结果超出了查询时间范围

    废话少说,直接上SQL代码(有兴趣的测试验证一下),下面这个查询语句为什么将2008-11-27的记录查询出来了呢?这个是同事遇到的一个问题,个人设计了一个例子. USE AdventureWorks ...

  6. subprocess之check_out用法

    在python3中使用subprocess的check_out方法时,因为该输出为byte类型,所以如果要查看具体的内容时需要进行转码,如果转码不对话,会影响内容输出的可读性,如下: #1,输出解码不 ...

  7. R-4 方差分析

    本节内容: 1:方差分析的原理 2:单因数方差分析 .双因数分析 3:交互项 一:方差分析是原理 方差分析原理 对总体均值的假设检验,有三种情况:1.总体均值与某个常数进行比较:2.两个总体均值之间的 ...

  8. FreeRTOS操作系统教程发布,支持F103,F407和F429,配套145个例子,1200页教程

    前言说明:1. 首先感谢大家对我们安富莱电子的支持. 2. FreeRTOS最大的优势就是开源免费,商业使用的话不需要用户公开源代码,也不存在任何版权问题,是当前小型嵌入式操作系统   市场使用率最高 ...

  9. 【linux命令 】文件特殊权限(SUID、SGID、SBIT)

    chmod 2770 /home/admins,刚看到这个命令,有点不解,后边770分别表示用户,组,其他人,前面的2不知道代表的是什么意思.百度之后发现2是代表八进制数,也是一种权限,它的三个bit ...

  10. 【数据结构】什么是二叉查找树(BST)

    什么是二叉查找树(BST) 1. 什么是BST 对于二叉树中的每个节点X,它的左子树中所有项的值都小于X中的项,它的右子树中所有项的值大于X中的项.这样的二叉树是二叉查找树. 以上是一颗二叉查找树,其 ...