[Codeforces Round #514 (Div. 2)] 解题分析

Codeforces传送门

A.Cashier

题目描述

Vasya has recently got a job as a cashier at a local store. His day at work is L L L minutes long. Vasya has already memorized n n n regular customers, the i − t h i-th ith of which comes after t i t_i ti minutes after the beginning of the day, and his service consumes l i l_i li minutes. It is guaranteed that no customer will arrive while Vasya is servicing another customer.

Vasya is a bit lazy, so he likes taking smoke breaks for a a a minutes each. Those breaks may go one after another, but Vasya must be present at work during all the time periods he must serve regular customers, otherwise one of them may alert his boss. What is the maximum number of breaks Vasya can take during the day?

输入输出格式

输入格式:

The first line contains three integers n n n, L L L and a a a ( 0 ≤ n ≤ 1 0 5 0≤n≤10^5 0n105, 1 ≤ L ≤ 1 0 9 1≤L≤10^9 1L109, 1 ≤ a ≤ L 1≤a≤L 1aL).

The i − t h i-th ith of the next n n n lines contains two integers t i t_i ti and l i l_i li ( 0 ≤ t i ≤ L − 1 0≤t_i≤L−1 0tiL1, 1 ≤ l i ≤ L 1≤l_i≤L 1liL). It is guaranteed that t i + l i ≤ t i + 1 t_i+l_i≤t_{i+1} ti+liti+1 and t n + l n ≤ L t_n+l_n≤L tn+lnL.

输出格式:

Output one integer — the maximum number of breaks.

输入输出样例

输入样例#1:

2 11 3
0 1
1 1

输出样例#1:

3

输入样例#2:

0 5 2

输出样例#2:

2

输入样例#3:

1 3 2
1 2

输出样例#3:

0

说明

In the first sample Vasya can take 3 3 3 breaks starting after 2 2 2, 5 5 5 and 8 8 8 minutes after the beginning of the day.

In the second sample Vasya can take 2 2 2 breaks starting after 0 0 0 and 2 2 2 minutes after the beginning of the day.

In the third sample Vasya can’t take any breaks.

解题分析

加一个 0 0 0, 加一个 L L L, 然后间隔除以 a a a下取整就好了。

代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define register
#define IN inline
#define R register
#define W while
#define gc getchar()
#define ll long long
#define db double
#define lowbit(i) ((i) & (-(i)))
const db PI = std::acos(-1.0);
int seq[300050];
int main(void)
{
	int a, b, cnt = 0, ans = 0;
	int n, l, k;
	scanf("%d%d%d", &n, &l, &k);
	for (R int i = 1; i <= n; ++i)
	{
		scanf("%d%d", &a, &b);
		seq[++cnt] = a, seq[++cnt] = a + b;
	}
	seq[++cnt] = 0, seq[++cnt] = l;
	std::sort(seq + 1, seq + 1 + cnt);
	for (R int i = 1; i < cnt; i += 2)
	ans += (seq[i + 1] - seq[i]) / k;
	printf("%d", ans);
}

B.Forgery

题目描述

Student Andrey has been skipping physical education lessons for the whole term, and now he must somehow get a passing grade on this subject. Obviously, it is impossible to do this by legal means, but Andrey doesn’t give up. Having obtained an empty certificate from a local hospital, he is going to use his knowledge of local doctor’s handwriting to make a counterfeit certificate of illness. However, after writing most of the certificate, Andrey suddenly discovered that doctor’s signature is impossible to forge. Or is it?

For simplicity, the signature is represented as an n × m n×m n×m grid, where every cell is either filled with ink or empty. Andrey’s pen can fill a 3 × 3 3×3 3×3square without its central cell if it is completely contained inside the grid, as shown below.

xxx
x.x
xxx

Determine whether is it possible to forge the signature on an empty n × m n×m n×m grid.

输入输出格式

输入格式:

The first line of input contains two integers n n n and m m m ( 3 ≤ n , m ≤ 1000 3≤n,m≤1000 3n,m1000).

Then n n n lines follow, each contains m m m characters. Each of the characters is either., representing an empty cell, or #, representing an ink filled cell.

输出格式:

If Andrey can forge the signature, output YES. Otherwise output NO.

You can print each letter in any case (upper or lower).

输入输出样例

输入样例#1:

3 3
###
#.#
###

输出样例#1:

YES

输入样例#2:

3 3
###
###
###

输出样例#2:

NO

输入样例#3:

4 3
###
###
###
###

输出样例#3:

YES

输入样例#4:

5 7
.......
.#####.
.#.#.#.
.#####.
.......

输出样例#4:

YES

解题分析

一开始想这个图形是不是有什么特殊性质, 然后忽然发现 n , m ≤ 1000 n,m\leq 1000 n,m1000

直接枚举每个格子看作为左上角是不是可以涂色, 如果可以涂就涂一下, 最后看有没有没涂到的地方就好。

代码如下:(略宽…)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define register
#define IN inline
#define R register
#define W while
#define gc getchar()
#define ll long long
#define db double
#define lowbit(i) ((i) & (-(i)))
const db PI = std::acos(-1.0);
#define MX 1005
char mp[MX][MX];
int tim[MX][MX];
int n, m;
IN bool check(R int x, R int y)
{
	return ((mp[x][y] == '#') & (mp[x][y + 1] == '#') & (mp[x][y + 2] == '#') & (mp[x + 1][y] == '#') & (mp[x + 1][y + 2] == '#') & (mp[x + 2][y] == '#') & (mp[x + 2][y + 1] == '#') & (mp[x + 2][y + 2] == '#'));
}
IN void work(R int x, R int y)
{
	tim[x][y]++;
	tim[x][y + 1]++;
	tim[x][y + 2]++;
	tim[x + 1][y]++;
	tim[x + 1][y + 2]++;
	tim[x + 2][y]++;
	tim[x + 2][y + 1]++;
	tim[x + 2][y + 2]++;
}
IN void fil(R int x, R int y)
{
	if(x + 2 > n || y + 2 > m) return;
	if(check(x, y)) work(x, y);
}
int main(void)
{
	scanf("%d%d", &n, &m);
	for (R int i = 1; i <= n; ++i)
	scanf("%s", mp[i] + 1);
	for (R int i = 1; i <= n; ++i)
	for (R int j = 1; j <= m; ++j)
	{
		if(mp[i][j] == '#') fil(i, j);
	}
	for (R int i = 1; i <= n; ++i)
	for (R int j = 1; j <= m; ++j) if(mp[i][j] == '#' && (!tim[i][j])) return puts("NO"), 0;
	puts("YES");
}

C. Sequence Transformation

题目描述

Let’s call the following process a transformation of a sequence of length n n n.

If the sequence is empty, the process ends. Otherwise, append the greatest common divisor ( G C D GCD GCD) of all the elements of the sequence to the result and remove one arbitrary element from the sequence. Thus, when the process ends, we have a sequence of n n n integers: the greatest common divisors of all the elements in the sequence before each deletion.

You are given an integer sequence 1 , 2 , … , n 1,2,…,n 1,2,,n. Find the lexicographically maximum result of its transformation.

A sequence a 1 , a 2 , … , a n a_1,a_2,…,a_n a1,a2,,anis lexicographically larger than a sequence b 1 , b 2 , … , b n b_1,b_2,…,b_n b1,b2,,bn, if there is an index i i i such that a j = b j a_j=b_j aj=bj for all j < i j<i j<i, and a i > b i a_i>b_i ai>bi.

输入输出格式

输入格式:

The first and only line of input contains one integer n n n ( 1 ≤ n ≤ 1 0 6 1≤n≤10^6 1n106).

输出格式:

Output n n n integers — the lexicographically maximum result of the transformation.

输入输出样例

输入样例#1:

3

输出样例#1:

1 1 3

输入样例#2:

2

输出样例#2:

1 2

输入样例#3:

1

输出样例#3:

1

解题分析

看起来很水的样例其实好心地提醒了我们…

首先我们肯定会先将所有奇数删掉, 这样就可以提出一个 2 2 2, 而如果要提出其他的约数肯定(???)要多删一些。

然后我们发现这样可以递归处理提出 2 2 2之后的那个数列。

但这样就是对的吗? 我们可以看下样例 1 1 1, 发现 3 3 3的时候需要特判。

这样就能 A A A了。

代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define register
#define IN inline
#define R register
#define W while
#define gc getchar()
#define ll long long
#define db double
#define lowbit(i) ((i) & (-(i)))
#define MX 1000050
const db PI = std::acos(-1.0);
int n;
void solve(R int len, R int mul)
{
	if(len == 1) return printf("%d ", (int)pow(2, mul)), void();
	if(len == 3) return printf("%d %d %d", (int)pow(2, mul), (int)pow(2, mul), (int)pow(2, mul) * 3), void();
	int num = (len + 1) >> 1;
	int ans = pow(2, mul);
	for (R int i = 1; i <= num; ++i) printf("%d ", ans);
	solve(len >> 1, mul + 1);
}
int main(void)
{
	scanf("%d", &n);
	solve(n, 0);
}

D. Nature Reserve

题目描述

There is a forest that we model as a plane and live n n n rare animals. Animal number i i i has its lair in the point ( x i , y i ) (x_i,y_i) (xi,yi). In order to protect them, a decision to build a nature reserve has been made.

The reserve must have a form of a circle containing all lairs. There is also a straight river flowing through the forest. All animals drink from this river, therefore it must have at least one common point with the reserve. On the other hand, ships constantly sail along the river, so the reserve must not have more than one common point with the river.

For convenience, scientists have made a transformation of coordinates so that the river is defined by y = 0 y=0 y=0. Check whether it is possible to build a reserve, and if possible, find the minimum possible radius of such a reserve.

输入输出格式

输入格式:

The first line contains one integer n n n ( 1 ≤ n ≤ 1 0 5 1≤n≤10^5 1n105) — the number of animals.

Each of the next n n n lines contains two integers x i x_i xi, y i y_i yi ( − 1 0 7 ≤ x i , y i ≤ 1 0 7 −10^7≤x_i,y_i≤10^7 107xi,yi107) — the coordinates of the i − t h i-th ith animal’s lair. It is guaranteed that y i ≠ 0 y_i≠0 yi̸=0. No two lairs coincide.

输出格式:

If the reserve cannot be built, print − 1 −1 1. Otherwise print the minimum radius. Your answer will be accepted if absolute or relative error does not exceed 1 0 − 6 10^{−6} 106.

Formally, let your answer be a a a, and the jury’s answer be b b b. Your answer is considered correct if ∣ a − b ∣ m a x ( 1 , ∣ b ∣ ) \frac{|a-b|}{max(1,|b|)} max(1,b)ab.

输入输出样例

输入样例#1:

1
0 1

输出样例#1:

0.5

输入样例#2:

3
0 1
0 2
0 -3

输出样例#2:

-1

输入样例#3:

2
0 1
1 1

输出样例#3:

0.625

解题分析

比赛的时候一直去想凸包了, 然后发现好像咋搞都不可能小于 O ( N 2 ) O(N^2) O(N2)的样子。

其实还有一个很好的条件没有用: 切 y = 0 y=0 y=0这条直线。

那么如果半径是 R \mathcal{R} R, 圆心可能的位置也就在一条平行于 y y y轴的直线上面。

那么二分这个半径, 对于一个点 ( x , y ) (x,y) (x,y)在这个直线上有一段区间 [ l , r ] [l,r] [l,r], 在这段区间内圆心到这个点的距离是 ≤ R \leq \mathcal{R} R的,如果有解即所有区间有公共部分。

精度十分爆炸, 用 l o n g   d o u b l e long\ double long double

代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define register
#define IN inline
#define R register
#define W while
#define gc getchar()
#define ll long long
#define db long double
#define lowbit(i) ((i) & (-(i)))
#define MX 100050
#define EPS 1e-8
using std::cin; using std::cout;
template <class T>
IN T sqr(const T &x) {return x * x;}
const db PI = std::acos(-1.0);
struct pt {db x, y;} dat[MX];
IN pt operator + (const pt &x, const pt &y) {return {x.x + y.x, x.y + y.y};}
IN pt operator - (const pt &x, const pt &y) {return {x.x - y.x, x.y - y.y};}
IN db operator * (const pt &x, const pt &y) {return x.x * y.y - x.y * y.x;}
int n, neg, pos;
IN bool check(db r)
{
	db lef = -2e16, rig = 2e16, lb, rb, del;
	for (R int i = 1; i <= n; ++i)
	{
		if(fabs(r - dat[i].y) > r) return false;
		del = std::sqrt(sqr(r) - sqr(r - dat[i].y));
		lb = dat[i].x - del, rb = dat[i].x + del;
		lef = std::max(lef, lb), rig = std::min(rig, rb);
		if(lef > rig) return false;
	}
	return true;
}
int main(void)
{
	std::ios_base::sync_with_stdio(false);
	cin.tie(0);
	cin >> n;
	for (R int i = 1; i <= n; ++i) 
	{
		cin >> dat[i].x >> dat[i].y;
		if(dat[i].y < 0) ++neg;
		else ++pos;
	}
	if(neg && pos) return puts("-1"), 0;
	if(neg) for (R int i = 1; i <= n; ++i) dat[i].y = -dat[i].y;
	db lef = 0, rig = 1e16, mid;
	int cnt = 250;
	W (cnt--)
	{
		mid = (lef + rig) / 2.0000000000;
		if(check(mid)) rig = mid;
		else lef = mid;
	}
	cout.precision(16);
	cout << std::fixed << rig;
}

E. Split the Tree

题目描述

You are given a rooted tree on  n n n vertices, its root is the vertex number  1 1 1. The  i − t h i-th ith vertex contains a number  w i w_i wi. Split it into the minimum possible number of vertical paths in such a way that each path contains no more than  L L L vertices and the sum of integers  w i w_i wi on each path does not exceed  S S S. Each vertex should belong to exactly one path.

输入输出格式

输入格式:

The first line contains three integers n n n, L L L, S S S ( 1 ≤ n ≤ 1 0 5 1≤n≤10^5 1n105, 1 ≤ L ≤ 1 0 5 1≤L≤10^5 1L105, 1 ≤ S ≤ 1 0 18 1≤S≤10^{18} 1S1018) — the number of vertices, the maximum number of vertices in one path and the maximum sum in one path.

The second line contains nn integers w 1 , w 2 , … , w n w_1,w_2,…,w_n w1,w2,,wn ( 1 ≤ w i ≤ 1 0 9 1≤w_i≤10^9 1wi109) — the numbers in the vertices of the tree.

The third line contains n − 1 n−1 n1 integers p 2 , … , p n p_2,…,p_n p2,,pn ( 1 ≤ p i < i 1≤p_i<i 1pi<i), where p i p_i pi is the parent of the i − t h i-th ith vertex in the tree.

输出格式:

Output one number  — the minimum number of vertical paths. If it is impossible to split the tree, output  − 1 −1 1.

输入输出样例

输入样例#1:

3 1 3
1 2 3
1 1

输出样例#1:

3

输入样例#2:

3 3 6
1 2 3
1 1

输出样例#2:

2

输入样例#3:

1 1 10000
10001

输出样例#3:

-1

解题分析

比赛的时候知道要贪心取向上延伸最远的, 但不知道怎么维护…

WOC, 这TM不就一个倍增吗??

下次比赛的时候一定要先睡一觉…

代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 100050
#define ll long long
int top[MX], dep[MX], fat[MX][18], to[MX], head[MX], val[MX];
ll pre[MX], mx;
int dot, lim, ans, cnt, lg;
struct Edge {int to, nex;} edge[MX << 1];
IN void add(R int from, R int to) {edge[++cnt] = {to, head[from]}, head[from] = cnt;}
void DFS(R int now)
{
	pre[now] = pre[fat[now][0]] + val[now];
	to[now] = now;
	R int lm = lim;
	for (R int i = 1; i < lg; ++i) fat[now][i] = fat[fat[now][i - 1]][i - 1];
	for (R int i = lg - 1; ~i; --i)
	{
		if((!fat[to[now]][i]) || (1 << i) > lm) continue;
		if(pre[now] - pre[fat[to[now]][i]] + val[fat[to[now]][i]] <= mx)
		lm -= (1 << i), to[now] = fat[to[now]][i];
	}
	for (R int i = head[now]; i; i = edge[i].nex)
	{
		dep[edge[i].to] = dep[now] + 1;
		fat[edge[i].to][0] = now;
		DFS(edge[i].to);
	}
}
int solve(R int now)
{
	int ret = 0, best = -1;
	for (R int i = head[now]; i; i = edge[i].nex)
	{
		ret += solve(edge[i].to);
		if(top[edge[i].to] == edge[i].to) continue;
		if(best == -1 || dep[top[edge[i].to]] < dep[best]) best = top[edge[i].to];
	}
	if(best == -1) ++ret, best = to[now];
	top[now] = best;
	return ret;
}
int main(void)
{
	int a;
	scanf("%d%d%I64d", &dot, &lim, &mx); --lim; lg = log2(dot) + 1;
	for (R int i = 1; i <= dot; ++i) {scanf("%d", &val[i]); if(val[i] > mx) return puts("-1"), 0;}
	for (R int i = 2; i <= dot; ++i) scanf("%d", &a), add(a, i);
	DFS(1); printf("%d", solve(1));
}

你可能感兴趣的:(Codeforces)