Codeforces Round #786 (Div. 3)补题

官网链接

E. Breaking the Wall

Monocarp plays “Rage of Empires II: Definitive Edition” — a strategic computer game. Right now he’s planning to attack his opponent in the game, but Monocarp’s forces cannot enter the opponent’s territory since the opponent has built a wall.

The wall consists of n sections, aligned in a row. The i-th section initially has durability ai. If durability of some section becomes 0 or less, this section is considered broken.

To attack the opponent, Monocarp needs to break at least two sections of the wall (any two sections: possibly adjacent, possibly not). To do this, he plans to use an onager — a special siege weapon. The onager can be used to shoot any section of the wall; the shot deals 2 damage to the target section and 1 damage to adjacent sections. In other words, if the onager shoots at the section x, then the durability of the section x decreases by 2, and the durability of the sections x−1 and x+1 (if they exist) decreases by 1 each.

Monocarp can shoot at any sections any number of times, he can even shoot at broken sections.

Monocarp wants to calculate the minimum number of onager shots needed to break at least two sections. Help him!

Input
The first line contains one integer n (2 ≤ n ≤ 2⋅105) — the number of sections.

The second line contains the sequence of integers a1,a2,…,an (1 ≤ ai ≤ 106), where ai is the initial durability of the i-th section.

Output
Print one integer — the minimum number of onager shots needed to break at least two sections of the wall.
Examples
input
5
20 10 30 10 20
output
10

input
3
1 8 1
output
1

input
6
7 6 6 8 5 8
output
4

input
6
14 3 8 10 15 4
output
4

input
4
1 100 100 1
output
2

input
3
40 10 10
output
7

Note
In the first example, it is possible to break the 2-nd and the 4-th section in 10 shots, for example, by shooting the third section 10 times. After that, the durabilities become [20,0,10,0,20]. Another way of doing it is firing 5 shots at the 2-nd section, and another 5 shots at the 4-th section. After that, the durabilities become [15,0,20,0,15].

In the second example, it is enough to shoot the 2-nd section once. Then the 1-st and the 3-rd section will be broken.

In the third example, it is enough to shoot the 2-nd section twice (then the durabilities become [5,2,4,8,5,8]), and then shoot the 3-rd section twice (then the durabilities become [5,0,0,6,5,8]). So, four shots are enough to break the 2-nd and the 3-rd section.

题解:
分三种情况讨论:
1、两个数间隔大于1
2、两个数间隔为1
3、两个数相邻
具体代码实现如下:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int,int> pii;

#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define lowbit(x)   ((x)&(-x))
#define fi first
#define se second
#define endl '\n'
#define pb push_back

template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }

template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char c = getchar();
    while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
    while (c <= '9' && c >= '0') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
    x *= f;
}

int main()
{
	IOS;
	int n;
	cin >> n;
    vector<int> a(n);
    for(int i = 0;i < n;i++)	cin >> a[i];

    vector<int> b = a;
	sort(b.begin(), b.end());
	int ans = (b[0] + 1) / 2 + (b[1] + 1) / 2;//第一种情况
	//第二种情况
	for(int i = 0;i + 2 < n;i++)	ans = min(ans,min(a[i],a[i + 2]) + (abs(a[i] - a[i + 2]) + 1) / 2);
	//第三种情况
	for(int i = 0;i + 1 < n;i++)
	{
		int mi = min(a[i],a[i + 1]),mx = max(a[i],a[i + 1]);
		if(mx >= mi * 2)	ans = min(ans,(mx + 1) / 2);
		else	ans = min(ans,(mx + mi + 2) / 3);
	}

	cout << ans << endl;
    return 0;
}

F. Desktop Rearrangement

Your friend Ivan asked you to help him rearrange his desktop. The desktop can be represented as a rectangle matrix of size n×m consisting of characters ‘.’ (empty cell of the desktop) and ‘*’ (an icon).

The desktop is called good if all its icons are occupying some prefix of full columns and, possibly, the prefix of the next column (and there are no icons outside this figure). In other words, some amount of first columns will be filled with icons and, possibly, some amount of first cells of the next (after the last full column) column will be also filled with icons (and all the icons on the desktop belong to this figure). This is pretty much the same as the real life icons arrangement.

In one move, you can take one icon and move it to any empty cell in the desktop.

Ivan loves to add some icons to his desktop and remove them from it, so he is asking you to answer q queries: what is the minimum number of moves required to make the desktop good after adding/removing one icon?

Note that queries are permanent and change the state of the desktop.

Input
The first line of the input contains three integers n, m and q (1 ≤ n,m ≤ 1000;1 ≤ q ≤ 2⋅105) — the number of rows in the desktop, the number of columns in the desktop and the number of queries, respectively.

The next n lines contain the description of the desktop. The i-th of them contains m characters ‘.’ and ‘*’ — the description of the i-th row of the desktop.

The next q lines describe queries. The i-th of them contains two integers xi and yi (1 ≤ xi ≤ n;1 ≤ yi ≤ m) — the position of the cell which changes its state (if this cell contained the icon before, then this icon is removed, otherwise an icon appears in this cell).

Output
Print q integers. The i-th of them should be the minimum number of moves required to make the desktop good after applying the first i queries.

Examples
在这里插入图片描述
在这里插入图片描述
知识点:
线段树组 + 二维坐标转化为一维坐标的方法

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int,int> pii;

#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define lowbit(x)   ((x)&(-x))
#define fi first
#define se second
#define endl '\n'
#define pb push_back

template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }

template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char c = getchar();
    while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
    while (c <= '9' && c >= '0') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
    x *= f;
}

const int N  = 1010;
int n,m,q;
char g[N][N];
struct Fenwick
{
	const int n;
	vector<int> tr;
	Fenwick(int n):n(n),tr(n + 1){};
	void add(int x,int c){
		for(int i = x;i <= n;i += i & -i)	tr[i] += c;
	}
	int sum(int x){
		int res = 0;
		for(int i = x;i ;i -= i & -i){
			res += tr[i];
		}
		return res;
	}
};

int get(int x,int y){
	return (y - 1) * n + x;
}

int main()
{
	IOS;
	cin >> n >> m >> q;

	int cnt = 0;
	Fenwick fen(n * m);
	for(int i = 1;i <= n;i++)
		for(int j = 1;j <= m;j++)
		{
			cin >> g[i][j];
			if(g[i][j] == '*')	fen.add(get(i,j),1),cnt++;
		}

	while(q--)
	{
		int x,y;
		cin >> x >> y;
		if(g[x][y] == '.')
		{
			g[x][y] = '*';
			fen.add(get(x,y),1);
			cnt++;
		}
		else
		{
			g[x][y] = '.';
			fen.add(get(x,y),-1);
			cnt--; 
		}
		cout << cnt - fen.sum(cnt) << endl;
	}
    return 0;
}
/*题意:一个n * m的二维平面上有若干个点,定义平面good为图标总是排满一列后再从上到下排满下一列的平面。
二维坐标转为一维坐标://要想用树状数组最重要还是这步转为一维坐标
(x,y) = ((y - 1) * n + x)
而且这个二维坐标转为一维坐标是按列排的,如果写成((x - 1) * m + y)就是按行排的了!
*/

G. Remove Directed Edges

You are given a directed acyclic graph, consisting of n vertices and m edges. The vertices are numbered from 1 to n. There are no multiple edges and self-loops.

Let inv be the number of incoming edges (indegree) and outv be the number of outgoing edges (outdegree) of vertex v.

You are asked to remove some edges from the graph. Let the new degrees be in′v and out′v.

You are only allowed to remove the edges if the following conditions hold for every vertex v:

1、in′v<inv or in′v=inv=0;
2、out′v<outv or out′v=outv=0.

Let’s call a set of vertices S cute if for each pair of vertices v and u (v≠u) such that v∈S and u∈S, there exists a path either from v to u or from u to v over the non-removed edges.

What is the maximum possible size of a cute set S after you remove some edges from the graph and both indegrees and outdegrees of all vertices either decrease or remain equal to 0?

Input
The first line contains two integers n and m (1 ≤ n ≤ 2⋅105; 0 ≤ m ≤ 2⋅105) — the number of vertices and the number of edges of the graph.

Each of the next m lines contains two integers v and u (1 ≤ v,u ≤ n; v ≠ u) — the description of an edge.

The given edges form a valid directed acyclic graph. There are no multiple edges.

Output
Print a single integer — the maximum possible size of a cute set S after you remove some edges from the graph and both indegrees and outdegrees of all vertices either decrease or remain equal to 0.

Examples
input
3 3
1 2
2 3
1 3
output
2

input
5 0
output
1

input
7 8
7 1
1 3
6 2
2 3
7 2
2 4
7 3
6 3
output
3
Note
In the first example, you can remove edges (1,2) and (2,3). in=[0,1,2], out=[2,1,0]. in′=[0,0,1], out′=[1,0,0]. You can see that for all v the conditions hold. The maximum cute set S is formed by vertices 1 and 3. They are still connected directly by an edge, so there is a path between them.

In the second example, there are no edges. Since all inv and outv are equal to 0, leaving a graph with zero edges is allowed. There are 5 cute sets, each contains a single vertex. Thus, the maximum size is 1.

In the third example, you can remove edges (7,1), (2,4), (1,3) and (6,2). The maximum cute set will be S={7,3,2}. You can remove edge (7,3) as well, and the answer won’t change.

Here is the picture of the graph from the third example:
在这里插入图片描述

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int,int> pii;

#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define debug printf("debug\n");
#define lowbit(x)   ((x)&(-x))
#define fi first
#define se second
#define endl '\n'
#define pb push_back

template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }

template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char c = getchar();
    while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
    while (c <= '9' && c >= '0') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
    x *= f;
}

const int N = 2e5+10;
int n,m;
int h[N],e[N],ne[N],din[N],dout[N],f[N],idx;

void add(int a,int b)
{
	e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}

void dfs(int u)
{
	if(f[u])	return;//"记忆化"
	f[u] = 1;//自己一个点初始化为1
	if(dout[u] < 2)	return;//出度小于2是不行的, 因为还要删去一条边
	for(int i = h[u]; ~i;i = ne[i])
	{
		int j = e[i];
		dfs(j);
		if(din[j] >= 2)	f[u] = max(f[u],f[j] + 1);//入度必须大于等于2才能更新
	}
}

int main()
{
	IOS;
	cin >> n >> m;

	memset(h,-1,sizeof(h));
	for(int i = 1;i <= m;i++)
	{
		int u,v;
		cin >> u >> v;
		add(u,v);
		din[v]++,dout[u]++;
	}

	for(int i = 1;i <= n;i++)	dfs(i);

	int ans = 0;
	for(int i = 1;i <= n;i++)	ans = max(ans,f[i]);//遍历以i为起点的链,找出最长链

	cout << ans << endl;
	return 0;
}
/*
思路:
因为要删除边似的每个点的入度和出度要么减少要么仍然为0,那么满足条件的链子中的点必须得入度和出度都大于等于2,这样
删边的话该顶点的入度出度一定会发生变化,即满足条件。
*/
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值