20231111

2023/11/11

补昨天vp的906

div2 补题到E1还是挺不容易的

今天vp一场,打了一场,本来想去打周赛玩一下的,结果6点人还在食堂。。。

D - Doremy's Connecting Plan

题意:给定两个数字 n 、c和一个长度为n的数组 a,现有n个孤立点,第 i 个孤立点的权值为a_{i},现需要通过建边将所有点全部连通。在第 i 个点和第 j 个点建边需要满足条件:\sum a_{k} \geq i * j *c(k\in S)(S为 i 所在连通块的点和 j 所在连通块的点的集合)。判断能否建成连通图。

思路:赛时想到:因为两个点直接连边,他们成立的条件一定是不变的。然后两个连通块直接肯定选两个编号最小的连。

想到这里思路还是乱的,所以改做法,我们可以用数学的不等式简单推导得到若i和j可以连边,那个i或者j一定可以和1点连边。那么连边的对象就解决了。考虑顺序,我们要满足sum>=j*c-a[j],那么其实我们按不等式右边从小到大排序就行。因为我们判断的时候就把 比sum小的贡献全加进来,那么一定是 最优的

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define Acode ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
const int N = 2e6 + 10;
int a[N];
struct node
{
	int id, val;
	int suf;
} s[N];

bool cmp(node a, node b)
{
	return a.suf < b.suf;
}

void solve()
{
	int n, c;
	cin >> n >> c;
	for (int i = 1; i <= n; i++)
	{
		cin >> s[i].val;
		s[i].id = i;
		s[i].suf = i * c - s[i].val;
	}
	sort(s + 1 + 1, s + 1 + n, cmp);
	int res = s[1].val;
	for (int i = 2; i <= n; i++)
	{
		if (res >= s[i].suf)
		{
			res += s[i].val;
		}
		else
		{
			cout << "No\n";
			return;
		}
	}
	cout << "Yes\n";
}

signed main()
{
	Acode;
	int T = 1;
	cin >> T;
	while (T--)
	{
		solve();
	}
	return 0;
}

E1. Doremy's Drying Plan (Easy Version)

题意:2e5区间,每个区间会+1,任意删两个问最多有几个零。 数组长度也是2e5.

思路:考虑到数组长度也是2e5, k==2 那么就分为两种情况:1、我们删两个区间中1最多的两个区间,这里我们不考虑重叠部分可以删2的情况,这是后面一种情况;2、我们看每个值为2的点,考虑到数组长度也是2e5,所以我们可以遍历数组,当一个点的值为2的时候,我们就记录一下是哪两个区间覆盖了他,因为为2,最多有2e5个区间。然后再加上每个区间可以删除1的个数即可

实现:第一种:我们先做一次原数组前缀和,然后做1的个数的前缀和。然后可以O(1)知道每个区间的1的个数

第二种:我们用类似扫描线的思想,对每个+1,-1的事件排序。当有效的区间个数为2时,意味着这个点就是值为2,那么这个区间组合++,代表这个组合能删除2的个数+1.

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define Acode ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
const int N = 2e6 + 10;
int a[N], a1[N];
int l[N], r[N];
vector<array<int, 3>> evt;
map<pair<int, int>, int> mp;
void solve()
{
	evt.clear();
	mp.clear();
	int n, m, k;
	cin >> n >> m >> k;
	for (int i = 1; i <= n; i++)
	{
		a[i] = a1[i] = 0;
	}
	for (int i = 1; i <= m; i++)
	{
		cin >> l[i] >> r[i];
		a[l[i]]++;
		a[r[i] + 1]--;
		evt.push_back({l[i], 1, i});
		evt.push_back({r[i] + 1, -1, i});
	}
	int cnt0 = 0;
	for (int i = 1; i <= n; i++)
	{
		a[i] = a[i - 1] + a[i];
		if (!a[i])
			cnt0++;
	}
	for (int i = 1; i <= n; i++)
	{
		a1[i] = a1[i - 1];
		if (a[i] == 1)
			a1[i]++;
	}
	// for (int i = 1; i <= n; i++)
	// {
	// 	cerr << a[i] << " ";
	// }
	// cerr << endl;
	int res = 0;
	vector<int> alls;
	for (int i = 1; i <= m; i++)
	{
		int x = a1[r[i]] - a1[l[i] - 1];
		alls.push_back(x);
		// cerr << x << endl;
	}
	sort(alls.begin(), alls.end());
	sort(evt.begin(), evt.end());
	int ans = cnt0 + alls[m - 1] + alls[m - 2];
	set<int> st;
	int pos = 0;
	for (int i = 1; i <= n; i++)
	{
		while (pos < evt.size() && evt[pos][0] == i)
		{
			if (evt[pos][1] == 1)
			{
				st.insert(evt[pos][2]);
			}
			else
			{
				st.erase(evt[pos][2]);
			}
			pos++;
		}
		// cerr << st.size() << endl;
		if (st.size() == k)
		{
			int x = *(st.begin());
			int y = *(st.rbegin());
			// cerr << x << " " << y << endl;
			mp[{x, y}]++;
		}
	}
	for (auto it : mp)
	{
		int num = it.second;
		int x = it.first.first;
		int y = it.first.second;
		int res1 = a1[r[x]] - a1[l[x] - 1];
		int res2 = a1[r[y]] - a1[l[y] - 1];
		ans = max(ans, num + res1 + res2 + cnt0);
	}
	cout << ans << endl;
}

signed main()
{
	Acode;
	int T = 1;
	cin >> T;
	while (T--)
	{
		solve();
	}
	return 0;
}

下午 vp Codeforces Round 907 (Div. 2) solve(3/6)

D题失误了, 做法想的太复杂了,然后C题那个前后缀指针写的有点卡,双指针边界一直调不好(老毛病了),还好wa了一发就过了,B题多组数据,有个数组没清空不太应该

https://www.bilibili.com/video/BV17N4y1U7s6/?vd_source=7b3be65640481106bef731ef741a960f

晚上八点打了(AtCoder Beginner Contest 328)solve(5/7)

这把开局不知道自己是谁,什么错误都犯了。。。B题甚至WA了5次才发现return早了导致数据读不完。

后程打的不错,D题想了一会,突然想到一个挺秒的做法,就一发过了。E题一开始没看到只有8的数据范围,看到后就直接开始想dfs枚举。一开始认为如果是完全图的话会跑超时,但是他只有8。邻接矩阵存图,dfs标记打好就一发过了

https://www.bilibili.com/video/BV1q94y137Y1/?vd_source=7b3be65640481106bef731ef741a960f

今天打了两场,明天要好好补题了

posted @ 2023-11-11 22:22  ヤ﹎句号悠灬  阅读(59)  评论(0)    收藏  举报