补完一套div4,此图为证
提交记录
说明
题目链接
一共7个题,做出前5题,排到接近四千名了。前5题就是模拟或者像前缀和后缀和之类的简单题,没什么好说的。比较难想的是F,好想但是细节多难调的是压轴题G。
A题 Medium Number
// cf div4.cpp : 定义控制台应用程序的入口点。
//
//#include "stdafx.h"
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t; cin >> t;
while (t--) {
int a, b, c;
cin >> a >> b >> c;
cout << a + b+c - min(a, min(b, c)) - max(a, max(b, c)) << endl;
}
//system("pause");
return 0;
}
B题 Atilla’s Favorite Problem
// cf div4.cpp : 定义控制台应用程序的入口点。
//
//#include "stdafx.h"
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t; cin >> t;
while (t--) {
int n; cin >> n;
string s; cin >> s;
int maxn = 'a' - '0';
for (int i = 0; i < n; i++) {
int x = s[i] - '0';
maxn = max(maxn, x);
}
cout << maxn - 'a'+'0' + 1 << endl;
}
//system("pause");
return 0;
}
C题 Advantage
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
int s[maxn];
int main()
{
int t; cin >> t;
while (t--) {
int n; cin >> n;
int maxx1 = -1e9, idmax1 = 0, maxx2 = -1e9, idmax2 = 0;
for (int i = 1; i <= n; i++) {
cin >> s[i];
if (s[i] > maxx1)maxx1 = s[i], idmax1 = i;
}
for (int i = 1; i <= n; i++) {
if (i == idmax1)continue;
if (s[i] > maxx2)maxx2 = s[i], idmax2 = i;
}
for (int i = 1; i <= n; i++) {
if (i != idmax1)cout << s[i] - maxx1;
else cout << s[i] - maxx2;
if (i != n)cout << " ";
}
cout << endl;
}
//system("pause");
return 0;
}
D题 Challenging Valleys
找最低的位置判两侧单调性。
// cf div4.cpp : 定义控制台应用程序的入口点。
//
//#include "stdafx.h"
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
int a[maxn];
int main()
{
int t; cin >> t;
while (t--) {
int n; cin >> n;
bool flag = false;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
int l = 1, r = 1;
bool pd1 = true, pd2 = true;
for (int i = 0; i<n-1; i++) {
if (a[i+1] < a[i])pd1=false;
}
for (int i = 0; i<n-1; i++) {
if (a[i + 1] > a[i])pd2 = false;
}
if (pd1 == true || pd2 == true)flag = true;
int minpos = -1, minn = 1e9;
for (int i = 0; i < n; i++) {
if (a[i] < minn)minpos = i, minn = a[i];
}
bool pd3 = true, pd4 = true;
for (int i = minpos; i < n-1; i++) {
if (a[i+1] < a[i])pd3 = false;
}
for (int i = minpos; i >= 1; i--) {
if (a[i-1] < a[i])pd4 = false;
}
if (pd3 == true && pd4 == true)flag = true;
if (flag == true)puts("YES");
else puts("NO");
}
// system("pause");
return 0;
}
E题 Binary Inversions
分别求一遍前缀和和后缀和。
// cf div4.cpp : 定义控制台应用程序的入口点。
//
//#include "stdafx.h"
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
int a[maxn];
int cnt0f1[maxn], cnt0b0[maxn], cnt1f1[maxn], cnt1b0[maxn];
int cnt0[maxn], cnt1[maxn];
int main()
{
int t; cin >> t;
while (t--) {
memset(cnt0, 0, sizeof(cnt0));
memset(cnt1, 0, sizeof(cnt1));
int n; cin >> n;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
for (int i = 0; i < n-1; i++) {
if (a[i] == 1) {
cnt1[i+1]++;
}
}
for (int i = 1; i < n; i++) {
cnt1[i] += cnt1[i - 1];
}
for (int i = n - 1; i > 0; i--) {
if (a[i] == 0) {
cnt0[i - 1]++;
}
}
for (int i = n - 1; i > 0; i--) {
cnt0[i - 1] += cnt0[i];
}
//for (int i = 0; i < n; i++)cout << cnt0[i] << " ";
//cout << endl;
//for (int i = 0; i < n; i++)cout << cnt1[i] << " ";
//cout << endl;
long long ini = 0;
for (int i = 0; i < n; i++) {
if (a[i] == 1) {
ini += cnt0[i];
}
}
int maxx = -1e9;
for (int i = 0; i < n; i++) {
int x = cnt0[i];
int y = cnt1[i];
if (a[i] == 0) {
maxx = max(maxx, x - y);
}
else {
maxx = max(maxx, y - x);
}
}
maxx = max(maxx, 0);
cout << ini + maxx << endl;
}
//system("pause");
return 0;
}
F题 Quests
按照贪心的思路,先排序,然后二分答案。
// 11.21-cf-div4-F.cpp : 定义控制台应用程序的入口点。
//
//#include "stdafx.h"
#include<bits/stdc++.h>
using namespace std;
int n, d;
long long c;
const int maxn = 2e5 + 5;
int a[maxn];
int main()
{
int t; cin >> t;
while (t--) {
cin >> n >> c >> d;
for (int i = 1; i <= n; i++)cin >> a[i];
sort(a + 1, a + 1 + n, greater<int>());
if ((long long)a[1] * (long long)d < c) {
puts("Impossible"); continue;
}
long long sum = 0;
for (int i = 1; i <= min(n, d); i++)sum += a[i];
if (sum >= c) {
puts("Infinity"); continue;
}
int left = 1, right = d, mid, k;
while (left <= right) {
mid = (left + right) >> 1;
long long all = 0;
for (int i = 1; i <= min(mid, n); i++)all += a[i];
int res = d%mid;
int re = d / mid;
all *= re;
for (int i = 1; i <= min(res, n); i++)all += a[i];
if (all >= c) {
k = mid;
left = mid + 1;
}
else if (all < c)right = mid - 1;
}
k--;
cout << k << endl;
}
//system("pause");
return 0;
}
G题 SlavicG’s Favorite Problem
后来补这个题的时候我是用链式前向星写的,中间有些细节调了很久。
// 11.21-cf-div4-G.cpp : 定义控制台应用程序的入口点。
//
//#include "stdafx.h"
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;//双向图翻倍
struct node {
int next;
int to;
int w;
}edge[maxn];
int cnt, head[maxn], n, a, b;
map<int, bool> mp;
void dfs_a(int u, int fa, int cur) {
for (int i = head[u]; i != -1; i = edge[i].next) {
if (edge[i].to == b)continue;//a不能直接到b
if (edge[i].to != fa) {
mp[cur^edge[i].w] = true;//必须异或别人才能记,一开始是0不能记
dfs_a(edge[i].to, u, cur^edge[i].w);
}
}
}
bool flag;
void dfs_b(int u, int fa, int cur) {//有从某位置传送到a再到b的可能性
for (int i = head[u]; i != -1; i = edge[i].next) {
if (edge[i].to != fa) {
if (mp[cur^edge[i].w] == true) {
flag = true; return;
}
dfs_b(edge[i].to, u, cur^edge[i].w);
}
}
}
void add(int u, int v, int w) {
edge[cnt].next = head[u];
head[u] = cnt;
edge[cnt].w = w;
edge[cnt].to = v;
cnt++;
}
int main()
{
int t; cin >> t;
while (t--) {
mp.clear();
memset(head, -1, sizeof(head));
cin >> n >> a >> b;
cnt = 0;
for (int i = 1; i < n; i++) {//只有n-1个输入,不是0到n-1,是1到n-1
int u, v, w;
cin >> u >> v >> w;
add(u, v, w);
add(v, u, w);
}
//由于权值不会是0,不用特判a直接到b
dfs_a(a, -1, 0);
flag = false;
mp[0] = true;//若从a直接可以到b,那dfs_b有0出现
dfs_b(b, -1, 0);//若dfs_a中没有0,此时0也应该有
if (flag)puts("YES");
else puts("NO");
}
//system("pause");
return 0;
}
小结
需要强化的知识点:贪心、二分、建图、树上遍历