人生第一场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的更多相关文章

  1. Codeforces Round #545 (Div. 1) 简要题解

    这里没有翻译 Codeforces Round #545 (Div. 1) T1 对于每行每列分别离散化,求出大于这个位置的数字的个数即可. # include <bits/stdc++.h&g ...

  2. Codeforces Round #466 (Div. 2) Solution

    从这里开始 题目列表 小结 Problem A Points on the line Problem B Our Tanya is Crying Out Loud Problem C Phone Nu ...

  3. 老年OIer的Python实践记—— Codeforces Round #555 (Div. 3) solution

    对没错下面的代码全部是python 3(除了E的那个multiset) 题目链接:https://codeforces.com/contest/1157 A. Reachable Numbers 按位 ...

  4. Codeforces Round #545 (Div. 2) D 贪心 + kmp

    https://codeforces.com/contest/1138/problem/D 题意 两个01串s和t,s中字符能相互交换,问最多能得到多少个(可交叉)的t 题解 即将s中的01塞进t中, ...

  5. Codeforces Round #545 (Div. 2) D

    链接:http://codeforces.com/contest/1138/problem/D 啊啊啊啊啊啊,自闭啊,比赛的时候判断条件 if(s1[i-1]=='0') aa++;写成了 if(s1 ...

  6. Codeforces Round #545 (Div. 2)(D. Camp Schedule)

    题目链接:http://codeforces.com/contest/1138/problem/D 题目大意:给你两个字符串s1和s2(只包含0和1),对于s1中,你可以调换任意两个字符的位置.问你最 ...

  7. Codeforces Round #545 (Div. 2)(B. Circus)

    题目链接:http://codeforces.com/contest/1138/problem/B 题目大意:贼绕口的题目,就是给你两个字符串s1,s2,然后每一个人代表一列,第一列代表技能一每个人是 ...

  8. Codeforces Round 500 (Div 2) Solution

    从这里开始 题目地址 瞎扯 Problem A Piles With Stones Problem B And Problem C Photo of The Sky Problem D Chemica ...

  9. Codeforces Round #545 (Div. 2) E 强连通块 + dag上求最大路径 + 将状态看成点建图

    https://codeforces.com/contest/1138/problem/E 题意 有n个城市(1e5),有m条单向边(1e5),每一周有d天(50),对于每个城市假如在某一天为1表示这 ...

随机推荐

  1. redis cluster是如何做到集两家之长的

    站在读写分离的层次看redis的时候,redis和master和slave存在明显的主从关系,也就是说master处于管理状态,salve跟着大哥混,master给小弟slave发粮食[发送内存快照数 ...

  2. 使用VSTS的Git进行版本控制(一)——复制现有仓库

    使用VSTS的Git进行版本控制(一)--复制现有仓库 概述 Team Services支持两种类型的版本控制Git和Team Foundation Version Control (TFVC).以下 ...

  3. 记录一次spark连接mysql遇到的问题

    版权声明:本文为博主原创文章,未经博主允许不得转载 在使用spark连接mysql的过程中报错了,错误如下 08:51:32.495 [main] ERROR - Error loading fact ...

  4. spring静态代理和动态代理

    本节要点: Java静态代理 Jdk动态代理 1 面向对象设计思想遇到的问题 在传统OOP编程里以对象为核心,并通过对象之间的协作来形成一个完整的软件功能,由于对象可以继承,因此我们可以把具有相同功能 ...

  5. June 11. 2018 Week 24th, Monday

    Love is the beauty of the soul. 爱是灵魂之美. From Saint Augustine. The complete version of this quote goe ...

  6. 更高的压缩比,更好的性能–使用ORC文件格式优化Hive

    http://lxw1234.com/archives/2016/04/630.htm 关键字:orc.index.hive Hive从0.11版本开始提供了ORC的文件格式,ORC文件不仅仅是一种列 ...

  7. js 性能篇--dom 重绘 重排 节流

    浏览器下载完页面中的所有组件----HTML标记,Js,CSS,图片等之后会解析并生成两个内部数据结构: DOM树  -------- 表示页面结构 渲染树   -------- 表示DOM节点如何显 ...

  8. echarts修改上下左右的边距

    grid: {                top: '4%',                left: '3%',                right: '4%',            ...

  9. Java基础知识点(三)

    前言:准备将Java基础知识点总结成一个系列,用于平常复习并加深理解.每篇尽量做到短小精悍,便于阅读. 1.Math类中相关函数 Math.floor(x):返回不大于x的最大整数.eg:Math.f ...

  10. Java(使用JNA)调用DLL库与C#调用DLL库的对比

    前言:在项目中经常使用DLL库对硬件进行操作,在发卡过程中使用频率尤为多,今天就Java与C#中调用DLL库的使用区别做一个介绍,本文着重具体的代码编写,具体过程看以下代码. 前提条件: 笔者已经封装 ...