Codeforces Global Round 13
A(水题)
题目:
给出一个\(01\)序列,有2种操作:1.将某个位置取反;2.询问\(01\)序列中第\(k\)大的数
解析:
显然维护1的数目即可
#include<bits/stdc++.h>
using namespace std;
/*===========================================*/
int ones = 0;
const int maxn = 1e5 + 5;
int dat[maxn];
int main() {
	int n, q, a, b;
	scanf("%d%d", &n, &q);
	for (int i = 0; i < n; ++i)
	{
		scanf("%d", &dat[i]);
		ones += dat[i];
	};
	while (q--) {
		scanf("%d%d", &a, &b);
		if (a == 1) {
			--b;
			if (dat[b])
				--ones;
			else
				++ones;
			dat[b] = 1 - dat[b];
		}
		else {
			printf("%d\n", ones >= b);
		}
	}
}
B(贪心)
题目:
给出一张图,由\(n(n\le100)\)行(行从1开始编号),\(10^6+1\)列组成(列从0开始编号),在所给矩阵的每一行存在一个障碍,现在可以花费\(v\)使得障碍水平移动,\(u\)使得障碍竖直移动,问若要从\((1,0)\)可以到达\((n,10^6+1)\),最小花费是多少?
(题目所给障碍物水平移动范围不包含两端)
解析:
由于水平移动范围不包含两端,所以不会出现上下封闭的情况,那么只有一种情况下无法到达,即所有障碍形成一条连续线段,将图分割成左右两部分,在这样的情况下,分以下两种情况进行讨论:
- 如果这是一条笔直的线段,即障碍所在列全部相同,则考虑将相邻障碍物一个左移一个右移,或者将障碍物先水平移动再垂直移动到不同行,形成空缺
 - 如果不是笔直的,那么在可以在线段斜线处水平移动一次或者竖直移动一次,形成空缺
 
#include<bits/stdc++.h>
using namespace std;
/*===========================================*/
int ones = 0;
const int maxn = 105;
int ob[maxn];
int main() {
	int T;
	int n, u, v;
	scanf("%d", &T);
	while (T--)
	{
		bool left = true;
		scanf("%d%d%d", &n, &u, &v);
		for (int i = 0; i < n; ++i)
			scanf("%d", &ob[i]);
		int last = 0;
		bool equ = true, line = true;
		for (int i = 1; i < n; ++i)
		{
			if (abs(ob[i] - ob[i - 1]) > 1)
			{
				line = false;
				break;
			}
			if (ob[i] != ob[i - 1])
				equ = false;
		}
		if (line) {
			if (equ)
				printf("%d", min(2 * v, u + v));
			else
				printf("%d", min(u, v));
		}
		else
			printf("%d", 0);
		printf("\n");
	}
}
C(思维)
题目:
给出\(n\)个蹦床,每个蹦床有一个强度\(S_i\),如果身处\(i\)蹦床,会跳跃至\(i+S_i\)处,且每次蹦床被踩压后,强度会\(-1\),但至多减至1,现在可以从任意位置起跳,每次跳跃直到无蹦床可以踩压为止,问将所有蹦床强度降至\(1\),所最少需要的游戏次数
解析:
- 假设从\(i\)蹦床出发,他只会对\(\ge i\)的部分产生影响,所以如果全要降为\(1\),则需要从前到后的遍历蹦床,并将其强度减到\(1\)为止
 - 这就要求维护一个\(t\)数组,统计\(i\)之前的蹦床跳跃时对\(i\)的影响,显然仍需要跳跃的次数为\(\max(S_i-1-t_i,0)\)
 - 将\(i\)位置的强度降为1,则会踩压到\(i+2,i+3,...,i+S_i\)的所有蹦床,即所属\(t\)均要加\(1\)
 - 同时也不难发现,可能由于受之前影响的踩压次数过多(未遍历到\(i\)以前,\(S_i\)已经降为\(1\)了),就可以传递给下一个蹦床,即\(t[i+1]=\max(t_i-S_i+1,0)\)
 
注意:
- 答案需要开\(long\ long\)存储
 - 第\(i\)号蹦床对后序的影响,即\(+1\)过程,可以用差分数组维护
 
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e3 + 5;
int dat[maxn];
int t[maxn];
long long ret;
int main() {
	int T,n;
	scanf("%d", &T);
	while (T--) {
		ret = 0;
		scanf("%d", &n);
		for (int i = 0; i < n; ++i)
			scanf("%d", &dat[i]);
		memset(t, 0, sizeof(t));
		for (int i = 0; i < n; ++i) {
			int x = max(0, dat[i] - 1 - t[i]);
			ret += x;
			int end = min(n - 1, i + dat[i]);
			for (int j = i + 2; j <= end; ++j)
				++t[j];
			t[i + 1] += max(t[i] - dat[i] + 1, 0);
		}
		printf("%lld\n", ret);
	}
}
D(思维+位运算)
题目:
规定如果\(u\&v=v\),则\(u\)可达\(u+v\),现在给出\(u,v\),问是否可以从\(u\)到\(v\)
解析:
- 如果\(u\rightarrow v\),则\(u<v\)是显然的
 - 不难发现对于任意一个\(u\),对于所有\(u\)可达点的中间变量\(v'\),满足:\(v'\)中如果位数为1,则必有\(u\)中对应位也为\(1\),而\(u+v'\)可以使得\(1\)的位置向左移,如1101+0001=1110,且在\(1\)连续的情况下,可以选择性的消除任意个多余的\(1\),例如0111+0001=1000,或0111+0101=1100
 - 那么对于所给出的\(u\)与\(v\)只要保证每个\(v\)的每一位的右边位置,\(u\)的\(1\)比\(v\)多,则就可以通过不断左移或消除\(1\),获得所需要的\(v\)序列。换句话说即每个\(v\)中,位为\(1\)的右边位上还含有若干个未被抵消(使用)的\(u\)的1
 
附:
- \(+v'\)操作肯定不会使得\(u+v'>v\)原因在于,对于每个\(v\)如果有1,则他的右边\(u\)存在很多1,这两段二进制代码的差一定是大于等于1的,如100000与0011010
 - 如果当前\(u\)位也存在1,则可以将这些多余的1放在后续中被消除,这是一定能完成的。因为初始时保证\(u\le v\),如果二者\(1\)的数目不等,则必然存在\(v\)的一个最高位使得\(v\)中有\(1\),而\(u\)终没有
 
E(暴力+分治+树)
题目:
规定\(Fib-tree\)必须满足以下条件
- 顶点数为\(Fibonacci数\)
 - 只有一个顶点或者可以通过消除某条边将树分割成两个\(Fib-tree\)
 
现在给出树的边,问是否是一个\(Fib-tree\)
解析:
首先对顶点数进行判定是否为\(Fibonacci数\)
如若这个树可以分割成两个子\(Fib-tree\),则一定能肯定两个子树的顶点数为\(fib[k-1],fib[k-2]\),同时也可以证明,如果存在多条(最多两条,由树的定义可知)可以分割的边,则消除任意一条可行边不会影响结果
证明:如果存在两条边分割子树顶点数为\(fib[k-1],fib[k-2]\),如果使用某一条可行边将其分割,另一条可行边一定是在\(fib[k-1]\)对应的子树中,会将\(fib[k-1]\)分割为\(fib[k-2],fib[k-3]\),所以两条边是等价的

这样的情况下,构建一个\(getSize\)函数获取以某个点为根,子树的大小,如果子树大小为\(fib[k-1]\)或者\(fib[k-2]\)则考虑分割这条边,然后进行递归性的处理即可
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
vector<int> fib;
typedef pair<int, bool> P;
vector<P> e[maxn];
int siz[maxn];
int n;
void no() { printf("NO"); exit(0); }
void getSize(int u, int fa) {
	siz[u] = 1;
	for (auto& i : e[u]) {
		if (i.second || i.first == fa) continue;
		getSize(i.first, u);
		siz[u] += siz[i.first];
	}
}
void cutEdge(int u, int fa, int k, int& pu, int& pv, int& kd) {
	for (auto& i : e[u]) {
		if (pu) return;
		if (i.second || i.first == fa) continue;
		if (siz[i.first] == fib[k - 1] || siz[i.first] == fib[k - 2]) {
			pu = u, pv = i.first;
			kd = siz[i.first] == fib[k - 1] ? k - 1 : k - 2;
			return;
		}
		cutEdge(i.first, u, k, pu, pv, kd);
	}
}
void Check(int u, int k) {
	if (k <= 1) return;
	getSize(u, 0);
	int pu = 0, pv = 0, kd = 0;
	cutEdge(u, 0, k, pu, pv, kd);
	if (!pu) no();
	for (auto& i : e[pu])
		if (i.first == pv) i.second = true;
	for (auto& i : e[pv])
		if (i.first == pu) i.second = true;
	Check(pv, kd);
	Check(pu, 2 * k - 3 - kd);
}
int main() {
	int u, v;
	scanf("%d", &n);
	fib.push_back(1), fib.push_back(1);;
	while (fib.back() < n)
		fib.push_back(fib[fib.size() - 1] + fib[fib.size() - 2]);
	for (int i = 1; i < n; ++i) {
		scanf("%d%d", &u, &v);
		e[u].push_back(P(v, false));
		e[v].push_back(P(u, false));
	}
	if (fib.back() != n) no();
	Check(1, fib.size() - 1);
	printf("YES");
}
												
											Codeforces Global Round 13的更多相关文章
- Codeforces Beta Round #13 C. Sequence (DP)
		
题目大意 给一个数列,长度不超过 5000,每次可以将其中的一个数加 1 或者减 1,问,最少需要多少次操作,才能使得这个数列单调不降 数列中每个数为 -109-109 中的一个数 做法分析 先这样考 ...
 - CodeForces Global Round 1
		
CodeForces Global Round 1 CF新的比赛呢(虽然没啥区别)!这种报名的人多的比赛涨分是真的快.... 所以就写下题解吧. A. Parity 太简单了,随便模拟一下就完了. B ...
 - Codeforces Global Round 1 - D. Jongmah(动态规划)
		
Problem Codeforces Global Round 1 - D. Jongmah Time Limit: 3000 mSec Problem Description Input Out ...
 - Codeforces Global Round 2 题解
		
Codeforces Global Round 2 题目链接:https://codeforces.com/contest/1119 A. Ilya and a Colorful Walk 题意: 给 ...
 - Codeforces Global Round 1 (A-E题解)
		
Codeforces Global Round 1 题目链接:https://codeforces.com/contest/1110 A. Parity 题意: 给出{ak},b,k,判断a1*b^( ...
 - Codeforces Global Round 3
		
Codeforces Global Round 3 A. Another One Bites The Dust 有若干个a,有若干个b,有若干个ab.你现在要把这些串拼成一个串,使得任意两个相邻的位置 ...
 - Codeforces Global Round 1 (CF1110) (未完结,只有 A-F)
		
Codeforces Global Round 1 (CF1110) 继续补题.因为看见同学打了这场,而且涨分还不错,所以觉得这套题目可能会比较有意思. 因为下午要开学了,所以恐怕暂时不能把这套题目补 ...
 - 【手抖康复训练1 】Codeforces Global Round 6
		
[手抖康复训练1 ]Codeforces Global Round 6 总结:不想复习随意打的一场,比赛开始就是熟悉的N分钟进不去时间,2333,太久没写题的后果就是:A 题手抖过不了样例 B题秒出思 ...
 - Codeforces Global Round 11 个人题解(B题)
		
Codeforces Global Round 11 1427A. Avoiding Zero 题目链接:click here 待补 1427B. Chess Cheater 题目链接:click h ...
 
随机推荐
- 《Proxy系列专题》:代理模式(静态、JDK、CGLib)
			
<Proxy系列专题>:代理模式(静态.JDK.CGLib)使用 现象:在如今互联网时代,项目的复杂度不断的提升,有些场景下需要一定的设计优化来支撑业务的扩展,如为了不改动原始类,但需要对 ...
 - Codeforces Round #690 (Div. 3)
			
第一次 ak cf 的正式比赛,不正式的是寒假里 div4 的 Testing Round,好啦好啦不要问我为什么没有 ak div4 了,差一题差一题 =.= 不知不觉已经咕了一个月了2333. 比 ...
 - c++中几种swap
			
在c与c++中,有多种办法可以通过函数交换传入的两数的值,但有容易有一些问题产生,因而本文将几种交换方式及容易出错的点进行了分类. 1.传引用这是c++中最常见方式如下: int swap1 (int ...
 - Consonant Fencity Gym - 101612C  暴力二进制枚举   Intelligence in Perpendicularia Gym - 101612I   思维
			
题意1: 给你一个由小写字母构成的字符串s,你可以其中某些字符变成大写字母.如果s中有字母a,你如果想把a变成大写,那s字符串中的每一个a都要变成A 最后你需要要出来所有的字符对,s[i]和s[i-1 ...
 - Linux运维博客大全
			
系统 U盘安装Linux详细步骤_hanxh7的博客-CSDN博客_u盘安装linux 使用U盘安装linux系统 - lwenhao - OSCHINA 各厂商服务器存储默认管理口登录信息(默认IP ...
 - Dcoker命令使用详解
			
Docker语法说明 docker [OPTIONS] COMMAND [arg...] OPTIONS --config=~/.docker :指定本地客户端配置文件. -D, --debug :开 ...
 - Java RMI 实现一个简单的GFS(谷歌文件系统)——介绍篇
			
本系列主要是使用Java RMI实现一个简单的GFS(谷歌文件系统,google file system),首先整体简单介绍下该项目. [为了更好的阅读以及查看其他篇章,请查看原文:https://w ...
 - 2018ACM上海大都会赛 F Color it【基础的扫描线】
			
题目:戳这里 题意:有n*m个点全为白色,q个圆,将q个圆内所有的点都染成黑色,问最后剩下多少白色的点. 解题思路:每一行当做一个扫描线,扫描所有的圆,记录每一行在圆中的点即可,O(n*q). 附ac ...
 - 2018大都会赛 A Fruit Ninja【随机数】
			
题目链接:戳这里 题意:一个平面里有n个点,问存不存在一条直线上有m个点,满足m >= n*x. 解题思路:0<x<1,且x小数点后只有1位,也就是说10*m > n.假设存在 ...
 - Linux 驱动框架---驱动中的并发
			
并发指多个执行单元被同时.并行的执行,而并发执行的单元对共享资源的访问就容易导致竟态.并发产生的情况分为抢占和并行(多核)和硬抢占(中断).Linux为解决这一问题增加了一系列的接口来解决并发导致的竟 ...