传送门

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. IO - 同步 异步 阻塞 非阻塞的区别,学习Swoole有帮助

    同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?本文较长需耐心阅读,基础 ...

  2. 从零开始手写 dubbo rpc 框架

    rpc rpc 是基于 netty 实现的 java rpc 框架,类似于 dubbo. 主要用于个人学习,由渐入深,理解 rpc 的底层实现原理. 前言 工作至今,接触 rpc 框架已经有很长时间. ...

  3. .net core 2.1 Nlog.Web.AspNetCore Nlog日志

    1.先创建 .net core Web 应用程序,选择API 2.安装 Nuget 包:Nlog.Web.AspNetCore install-package Nlog install-package ...

  4. cesium 圆圈警戒扫描(附源码下载)

    前言 cesium 官网的api文档介绍地址cesium官网api,里面详细的介绍 cesium 各个类的介绍,还有就是在线例子:cesium 官网在线例子,这个也是学习 cesium 的好素材. 内 ...

  5. 【iOS】Swipe与Pan区别分析

    By definition, a swipe gesture is necessarily also a pan gesture -- both involve translational movem ...

  6. 华为网络设备修改console密码

    user-interface con 0set authentication password cipher 新密码 有的版本为 <FW> system-view[FW] user-int ...

  7. openstack-neutron安装与配置

    一.实验目的: 1.理解neutron服务在OpenStack中的作用 2.掌握在控制节点上安装配置neutron的方法和步骤 3.掌握在计算节点上安装与配置neutron的方法和步骤 二.实验步骤: ...

  8. 由随机数rand5实现随机数rand7

    rand5表示生成随机数1,2,3,4,5 rand7表示生成随机数1,2,3,4,5,6,7 要通过rand5构造rand7现在可能没有什么思路,我们先试着用rand7生成rand5 rand7生成 ...

  9. vue定义全局date过滤器(自定义JS文件模块和Moment.js库)

    自定义dateFormat.js文件模块 dateFormat.js /** * 时间字符串 转 时间戳 * @param {String} time_str 时间字符串(格式"2014-0 ...

  10. Java面试题和解答(五)

    1.在Java中Executor和Executors的区别? Executor是线程池的顶层接口,它的实现类如下图所示: Executors是一个类,提供了多个静态方法,用于生成不同类型的线程池,如下 ...