官网链接
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,这样
删边的话该顶点的入度出度一定会发生变化,即满足条件。
*/