Codeforces Round #545 (Div. 1) Solution
人生第一场Div. 1
结果因为想D想太久不晓得Floyd判环法、C不会拆点、E想了个奇奇怪怪的set+堆+一堆乱七八糟的标记的贼难写的做法滚粗了qwq靠手速上分qwqqq
A. Skyscrapers
将行列各自离散化并记录下每一个值在行离散化时和列离散化时得到的值以及每一行、每一列出现的最大离散化值
对于每一行和每一列考虑其相交格子的两个离散化值,如果它们的差为\(\Delta\),就把它对应行列最大离散化值中较小的+\(\Delta\),最后两者取Max
#include<iostream>
#include<cstdio>
#include<ctime>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<queue>
#include<vector>
#define INF 0x3f3f3f3f
//This code is written by Itst
using namespace std;
inline int read(){
int a = 0;
char c = getchar();
bool f = 0;
while(!isdigit(c)){
if(c == '-') f = 1;
c = getchar();
}
while(isdigit(c)){
a = a * 10 + c - 48;
c = getchar();
}
return f ? -a : a;
}
#define PII pair < int , int >
int num[1007][1007] , h[1007][1007] , l[1007][1007] , N , M;
int main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
//freopen("out","w",stdout);
#endif
N = read(); M = read();
for(int i= 1 ; i <= N ; ++i)
for(int j = 1 ; j <= M ; ++j)
num[i][j] = read();
vector < PII > vec;
for(int i = 1 ; i <= N ; ++i){
vec.clear();
for(int j = 1 ; j <= M ; ++j)
vec.push_back(PII(num[i][j] , j));
sort(vec.begin() , vec.end());
int pre = 0 , cnt = 0;
for(auto t : vec){
cnt += pre != t.first;
h[i][t.second] = cnt;
pre = t.first;
}
h[i][0] = cnt;
}
for(int i = 1 ; i <= M ; ++i){
vec.clear();
for(int j = 1 ; j <= N ; ++j)
vec.push_back(PII(num[j][i] , j));
sort(vec.begin() , vec.end());
int pre = 0 , cnt = 0;
for(auto t : vec){
cnt += pre != t.first;
l[t.second][i] = cnt;
pre = t.first;
}
l[0][i] = cnt;
}
for(int i = 1 ; i <= N ; ++i){
for(int j = 1 ; j <= M ; ++j)
cout << max(h[i][0] + max(h[i][j] , l[i][j]) - h[i][j] , l[0][j] + max(h[i][j] , l[i][j]) - l[i][j]) << ' ';
cout << endl;
}
return 0;
}
B. Camp Schedule
KMP求出最长Border,因为最长的Border是两个串拼在一起时能够节约的最长的串。然后能放即放,最后剩下的乱放
#include<iostream>
#include<cstdio>
#include<ctime>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<queue>
#include<vector>
#define INF 0x3f3f3f3f
//This code is written by Itst
using namespace std;
char s[500007] , t[500007];
int nxt[500007];
int main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
//freopen("out","w",stdout);
#endif
scanf("%s %s" , s + 1 , t + 1);
int lS = strlen(s + 1) , lT = strlen(t + 1);
nxt[0] = -1;
for(int i = 1 ; i <= lT ; ++i){
int cur = nxt[i - 1];
while(cur != -1 && t[cur + 1] != t[i])
cur = nxt[cur];
nxt[i] = cur + 1;
}
int cntS0 = 0 , cntS1 = 0 , cntT0 = 0 , cntT1 = 0 , cntCir0 = 0 , cntCir1 = 0;
for(int i = 1 ; i <= lS ; ++i)
if(s[i] == '0') ++cntS0;
else ++cntS1;
for(int i = 1 ; i <= nxt[lT] ; ++i)
if(t[i] == '0') ++cntT0;
else ++cntT1;
for(int i = nxt[lT] + 1 ; i <= lT ; ++i)
if(t[i] == '0') ++cntCir0;
else ++cntCir1;
if(cntS0 >= cntT0 && cntS1 >= cntT1){
cntS0 -= cntT0; cntS1 -= cntT1;
for(int i = 1 ; i <= nxt[lT] ; ++i)
putchar(t[i]);
}
while(cntS0 >= cntCir0 && cntS1 >= cntCir1){
cntS0 -= cntCir0; cntS1 -= cntCir1;
for(int i = nxt[lT] + 1 ; i <= lT ; ++i)
putchar(t[i]);
}
while(cntS0){putchar('0'); --cntS0;}
while(cntS1){putchar('1'); --cntS1;}
return 0;
}
C. Museums Tour
PS:在status->execution time->最后一板可以看到我3993ms的好成绩qwq
拆点,对于一个点\(u\)拆成\(d\)个点\(u_0,u_1,...,u_{d-1}\),对于一条边\((u,v)\)拆成\(d\)条边\((u_i,v_{(i+1) \mod d})\),然后tarjan求SCC并顺带求出一个SCC中能够到达的博物馆数量,那么也就是要求选择一条从\(1_0\)所在的SCC开始的路径,使得经过的所有点能够到达的博物馆数量最多。在DAG上记搜一下即可。
注意:DAG上的路径的博物馆数量就是所有点的博物馆数量相加,而且不会重复计算博物馆。因为如果存在路径\((u_i,u_j)\),那么从\(u_j\)沿着与这条路径相同的路径绕\(d-1\)轮肯定会到达\(u_i\),所以会存在路径\((u_j,u_i)\),所以对于\(\forall i , j\),\(u_i\)和\(u_j\)不会存在拓扑先后顺序的关系,所以不会算重。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
//This code is written by Itst
using namespace std;
inline int read(){
int a = 0;
char c = getchar();
while(!isdigit(c))
c = getchar();
while(isdigit(c)){
a = a * 10 + c - 48;
c = getchar();
}
return a;
}
#define id(i,j) ((i - 1) * D + j)
const int MAXN = (1e5 + 1) * 50;
vector < int > ch[MAXN];
struct Edge{
int end , upEd;
}Ed[MAXN];
int head[MAXN] , dfn[MAXN] , low[MAXN] , stk[MAXN] , sum[MAXN] , in[MAXN] , ans[MAXN];
int cntEd , top , N , M , D , ts , cntSCC;
bool vis[MAXN] , ins[MAXN] , open[MAXN] , mrk[100003];
inline void addEd(int a , int b){
Ed[++cntEd] = (Edge){b , head[a]};
head[a] = cntEd;
}
void pop(int x){
++cntSCC;
vector < int > nd;
do{
int t = stk[top];
nd.push_back(t / D);
ins[t] = 0; in[t] = cntSCC;
if(!mrk[t / D] && open[t]){
mrk[t / D] = 1;
++sum[cntSCC];
}
}while(stk[top--] != x);
for(auto t : nd) mrk[t] = 0;
}
void tarjan(int x){
dfn[x] = low[x] = ++ts;
vis[x] = ins[x] = 1;
stk[++top] = x;
for(int i = head[x] ; i ; i = Ed[i].upEd){
if(!vis[Ed[i].end]) tarjan(Ed[i].end);
else if(!ins[Ed[i].end]) continue;
low[x] = min(low[x] , low[Ed[i].end]);
}
if(dfn[x] == low[x]) pop(x);
}
int dfs(int x){
if(ans[x] != -1) return ans[x];
ans[x] = 0;
for(auto t : ch[x]) ans[x] = max(ans[x] , dfs(t));
return ans[x] += sum[x];
}
inline char getc(){
char c = getchar();
while(!isdigit(c)) c = getchar();
return c;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
//freopen("out","w",stdout);
#endif
memset(ans , -1 , sizeof(ans));
N = read(); M = read(); D = read();
for(int i = 1 ; i <= M ; ++i){
int a = read() , b = read();
for(int j = 0 ; j < D ; ++j)
addEd(id(a , j) , id(b , (j + 1) % D));
}
for(int i = 1 ; i <= N ; ++i)
for(int j = 0 ; j < D ; ++j)
open[id(i , j)] = getc() - '0';
tarjan(0);
for(int i = 0 ; i <= id(N , (D - 1)) ; ++i)
if(in[i])
for(int j = head[i] ; j ; j = Ed[j].upEd)
if(in[Ed[j].end] && in[i] != in[Ed[j].end])
ch[in[i]].push_back(in[Ed[j].end]);
cout << dfs(in[0]) << endl;
return 0;
}
D. Cooperative Game
先使用Floyd判环法:找两个人,一个人走一步、一个人走两步,不断走直到这两个人在同一个点。假设其中一个人走了\(x + t\)步,另一个人走了\(2x + 2t\)步,然后再所有人一起走,至多\(3x + 3t\)步所有人就会走到一起。而在这之前肯定会有一段时间所有人已经到达同一个点,只是在环上走,所以当所有人第一次相遇的时候就刚好同时到达终点。
考虑步数,有\(t+x \equiv 2t + 2x \mod c\),即\(x + t \equiv 0 \mod c\),即\(x = c - t \mod c\)。所以前两个人的总步数为\(2(c - t \ mod c) + 2t \leq 2t + 2c\)步,最后所有人一起走要走\(t\)步,所以总共要走\(3t+2c\)步。
#include<bits/stdc++.h>
using namespace std;
int get(){
int x;
string s;
cin >> x;
for(int i = 1 ; i <= x ; ++i) cin >> s;
return x;
}
int main(){
do{
puts("next 0 1");
get();
puts("next 1");
}while(get() > 2);
do{
puts("next 0 1 2 3 4 5 6 7 8 9");
}while(get() > 1);
puts("done");
return 0;
}
E. Train Car Selection
注意到一次性加一段\(0\)的操作只有最前面的\(0\)会产生贡献
对于\(1\ k\)的情况,相当于之前所有的数都不可能会产生贡献
对于其他情况,记录当前所有一次函数的和,将\((i,a_i)\)看做平面上的一个点,那么会产生贡献的点只会出现在所有点的右上凸包上,使用单调栈维护。
#include<iostream>
#include<cstdio>
#include<queue>
#include<set>
//This code is written by Itst
using namespace std;
#define int long long
inline int read(){
int a = 0;
char c = getchar();
while(!isdigit(c))
c = getchar();
while(isdigit(c)){
a = a * 10 + c - 48;
c = getchar();
}
return a;
}
const int MAXN = 3e5 + 7;
#define ld long double
#define PII pair < int , int >
#define st first
#define nd second
PII st[MAXN];
int K , B , top , all;
ld getK(PII a , PII b){return (b.nd - a.nd) * 1.0 / (a.st - b.st);}
int calc(PII nd){return (nd.st - 1) * K + nd.nd + B;}
signed main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
//freopen("out","w",stdout);
#endif
all = read(); st[top = 1] = PII(1 , 0);
for(int M = read() ; M ; --M){
int tp = read();
if(tp == 1){st[top = 1] = PII(1 , 0); B = K = 0; all += read();}
else
if(tp == 2){
PII now = PII(all + 1 , -calc(PII(all + 1 , 0)));
while(top > 1 && getK(now , st[top]) >= getK(st[top] , st[top - 1]))
--top;
st[++top] = now;
all += read();
}
else{B += read(); K += read();}
while(top > 1 && calc(st[top]) >= calc(st[top - 1])) --top;
cout << st[top].st << ' ' << calc(st[top]) << endl;
}
return 0;
}
F. Matches Are Not a Child's Play
考虑一次\(up\)对原树的影响:对于原树中优先级最大的点\(u\)和当前\(up\)的点\(v\),以\(u,v\)为端点的这一条链一定会在最后被烧掉,而且一定是从\(u\)到\(v\)依次烧掉。而对于其他的部分,烧掉的顺序和之前的顺序是一样的。
所以考虑:每一次将树根\(u\)设为当前优先级最大的点,每一次\(up\ v\)操作时,给\(u\)到\(v\)的这一条链的颜色变为当前最大的优先级\(+1\),然后将\(v\)变为树根。注意到这两个操作都可以使用LCT完美解决。
最后考虑答案:一个compare操作显然是可以拆成两个when操作的,所以只需要考虑when操作。而when操作的答案就是:当前所有节点中颜色值比当前节点小的点的数量加上在当前点之前被烧掉的与它颜色相同的点的数量。前者可以使用树状数组维护颜色的前缀和;而在当前点之前被烧掉的与它同一个颜色的点就是将当前节点Splay成根节点之后右子树的大小。
#include<iostream>
#include<cstdio>
#include<queue>
//This code is written by Itst
using namespace std;
inline int read(){
int a = 0;
char c = getchar();
while(!isdigit(c))
c = getchar();
while(isdigit(c)){
a = a * 10 + c - 48;
c = getchar();
}
return a;
}
const int MAXN = 2e5 + 3;
int N , Q , cntCol;
namespace BIT{
int BIT[MAXN << 1];
#define lowbit(x) ((x) & -(x))
void add(int x , int num){
while(x <= N + Q){
BIT[x] += num;
x += lowbit(x);
}
}
int get(int x){
int sum = 0;
while(x){
sum += BIT[x];
x -= lowbit(x);
}
return sum;
}
}
using BIT::add; using BIT::get;
namespace LCT{
struct node{
int ch[2] , fa , col , sz;
bool mrk;
}Tree[MAXN];
bool nroot(int x){
return Tree[Tree[x].fa].ch[0] == x || Tree[Tree[x].fa].ch[1] == x;
}
bool son(int x){
return Tree[Tree[x].fa].ch[1] == x;
}
void pushup(int x){
Tree[x].sz = Tree[Tree[x].ch[0]].sz + Tree[Tree[x].ch[1]].sz + 1;
}
void rot(int x){
bool f = son(x);
int y = Tree[x].fa , z = Tree[y].fa , w = Tree[x].ch[f ^ 1];
Tree[x].fa = z;
if(nroot(y)) Tree[z].ch[son(y)] = x;
Tree[y].fa = x; Tree[x].ch[f ^ 1] = y;
Tree[y].ch[f] = w; if(w) Tree[w].fa = y;
pushup(y);
}
void mark(int x , bool f , int col){
if(!x) return;
Tree[x].col = col;
if(f){
swap(Tree[x].ch[0] , Tree[x].ch[1]);
Tree[x].mrk ^= 1;
}
}
void pushdown(int x){
mark(Tree[x].ch[0] , Tree[x].mrk , Tree[x].col);
mark(Tree[x].ch[1] , Tree[x].mrk , Tree[x].col);
Tree[x].mrk = 0;
}
void down_all(int x){
if(nroot(x)) down_all(Tree[x].fa);
pushdown(x);
}
void splay(int x){
down_all(x);
while(nroot(x)){
if(nroot(Tree[x].fa))
rot(son(x) == son(Tree[x].fa) ? Tree[x].fa : x);
rot(x);
}
pushup(x);
}
void access(int x){
for(int y = 0 ; x ; y = x , x = Tree[x].fa){
splay(x);
add(Tree[x].col , -(Tree[Tree[x].ch[0]].sz + 1));
Tree[x].ch[1] = y;
pushup(x);
}
}
void makeroot(int x){
access(x); splay(x);
mark(x , 1 , ++cntCol); add(cntCol , Tree[x].sz);
}
int query(int x){
splay(x);
return get(Tree[x].col - 1) + Tree[Tree[x].ch[1]].sz + 1;
}
}
using LCT::makeroot; using LCT::query;
namespace Tree{
struct Edge{
int end , upEd;
}Ed[MAXN << 1];
int head[MAXN] , in[MAXN] , cntEd;
inline void addEd(int a , int b){
Ed[++cntEd].end = b;
Ed[cntEd].upEd = head[a];
head[a] = cntEd;
++in[a];
}
void init(){
for(int i = 1 ; i < N ; ++i){
int a = read() , b = read();
addEd(a , b); addEd(b , a);
}
priority_queue < int , vector < int > , greater < int > > q;
for(int i = 1 ; i <= N ; ++i)
if(in[i] == 1) q.push(i);
while(!q.empty()){
int t = q.top(); q.pop();
add(LCT::Tree[t].col = ++cntCol , 1);
for(int i = head[t] ; i ; i = Ed[i].upEd){
if(--in[Ed[i].end] == 1)
q.push(Ed[i].end);
if(in[Ed[i].end] >= 1 || Ed[i].end == N)
LCT::Tree[t].fa = Ed[i].end;
}
}
}
}
inline char getc(){
char c = getchar();
while(!islower(c)) c = getchar();
return c;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
N = read(); Q = read(); Tree::init();
int a , b;
for(int i = 1 ; i <= Q ; ++i)
switch(getc()){
case 'u': makeroot(read()); break;
case 'w': printf("%d\n" , query(read())); break;
case 'c':
a = read(); b = read();
printf("%d\n" , query(a) > query(b) ? b : a);
break;
}
return 0;
}
Codeforces Round #545 (Div. 1) Solution的更多相关文章
- Codeforces Round #545 (Div. 1) 简要题解
这里没有翻译 Codeforces Round #545 (Div. 1) T1 对于每行每列分别离散化,求出大于这个位置的数字的个数即可. # include <bits/stdc++.h&g ...
- Codeforces Round #466 (Div. 2) Solution
从这里开始 题目列表 小结 Problem A Points on the line Problem B Our Tanya is Crying Out Loud Problem C Phone Nu ...
- 老年OIer的Python实践记—— Codeforces Round #555 (Div. 3) solution
对没错下面的代码全部是python 3(除了E的那个multiset) 题目链接:https://codeforces.com/contest/1157 A. Reachable Numbers 按位 ...
- Codeforces Round #545 (Div. 2) D 贪心 + kmp
https://codeforces.com/contest/1138/problem/D 题意 两个01串s和t,s中字符能相互交换,问最多能得到多少个(可交叉)的t 题解 即将s中的01塞进t中, ...
- Codeforces Round #545 (Div. 2) D
链接:http://codeforces.com/contest/1138/problem/D 啊啊啊啊啊啊,自闭啊,比赛的时候判断条件 if(s1[i-1]=='0') aa++;写成了 if(s1 ...
- Codeforces Round #545 (Div. 2)(D. Camp Schedule)
题目链接:http://codeforces.com/contest/1138/problem/D 题目大意:给你两个字符串s1和s2(只包含0和1),对于s1中,你可以调换任意两个字符的位置.问你最 ...
- Codeforces Round #545 (Div. 2)(B. Circus)
题目链接:http://codeforces.com/contest/1138/problem/B 题目大意:贼绕口的题目,就是给你两个字符串s1,s2,然后每一个人代表一列,第一列代表技能一每个人是 ...
- Codeforces Round 500 (Div 2) Solution
从这里开始 题目地址 瞎扯 Problem A Piles With Stones Problem B And Problem C Photo of The Sky Problem D Chemica ...
- Codeforces Round #545 (Div. 2) E 强连通块 + dag上求最大路径 + 将状态看成点建图
https://codeforces.com/contest/1138/problem/E 题意 有n个城市(1e5),有m条单向边(1e5),每一周有d天(50),对于每个城市假如在某一天为1表示这 ...
随机推荐
- 一句SQL完成动态分级查询
在最近的活字格项目中使用ActiveReports报表设计器设计一个报表模板时,遇到一个多级分类的难题:需要将某个部门所有销售及下属部门的销售金额汇总,因为下属级别的层次不确定,所以靠拼接子查询的方式 ...
- C# 利用SharpPcap实现网络包捕获嗅探
本文是利用SharpPcap实现网络包的捕获的小例子,实现了端口监控,数据包捕获等功能,主要用于学习分享. 什么是SharpPcap? SharpPcap 是一个.NET 环境下的网络包捕获框架,基于 ...
- MySQL针对对账数据,每天每个店只能产生一条对账记录,对数据库数据进行添加联合唯一索引设置
ALTER TABLE StoreDailyCheck ADD UNIQUE INDEX(StoreId,CheckDate);
- Scrapy代码实战
1.Spider爬虫代码 # -*- coding: utf-8 -*- import scrapy from yszd.items import YszdItem class YszdSpiderS ...
- JavaScript中解决计算精度丢失的问题
在做项目之前老师就给我们封装好了一个js文件,解决计算中丢失精度的一些函数,直接引用js文件就可以使用. eg: var numA = 0.1; var numB = 0.2; alert( numA ...
- C# DBHelper类 参考
using System;using System.Collections.Generic;using System.Text;using System.Configuration;using Sys ...
- Android Studio插件GsonFormat
GsonFormat插件用于在androidStudio 根据json自动生成class的字段和方法,极大提高了开发效率 一.安装GsonFormat插件 二.重启Android Studio,新建一 ...
- Lua代码规范
以下规范,是在Unity中使用Lua做为开发语言,仅供参考. 1.格式规范 1. lua文件名统一小写,中间一律不加下划线分割 2. 类名首字母大写,多个词组成的类名,每个词的首字母大写,中间一律不加 ...
- mybatis : ERROR. token : COMMA, pos : 373
查询的字段符号问题,可能是多了" , " 也可能是少了 " , " 仔细检查, 都能解决
- python3编写网络爬虫19-app爬取
一.app爬取 前面都是介绍爬取Web网页的内容,随着移动互联网的发展,越来越多的企业并没有提供Web页面端的服务,而是直接开发了App,更多信息都是通过App展示的 App爬取相比Web端更加容易 ...