Educational Codeforces Round 78

A题:暴力然后排序用string比较就好。


B题:找规律?可能emm
首先第i次加i,记前缀和为sum,要两个数字相等,至少sum>=两个数字的差。
我们进一步思考,当sum!=差的时候,记sum-dis=x。
如果x是偶数,x/=2,然后该数字x一定是出现在sum里面的数字,我们将x分给大的数字,那么大数字增加x,小数字减小x,就可以相等了。
当x是奇数,我们没有办法相等,继续加上i+1,i+2..直到奇偶一样。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
int t;
const int N = 1e5+10;
int n = 1e5;
int a, b;
ll sum[N];
void init()
{
	upd(i, 1, 1e5)
	{
		sum[i] = sum[i - 1] + i*1ll;
	}
	sort(sum, sum + n);
}
int main()
{
	t = read();
	while (t--)
	{
		init();
		a = read(), b = read();
		int dis = abs(b - a);
		int temp = lower_bound(sum, sum + n, dis) - sum;
		while ((sum[temp] % 2) != (dis % 2))temp++;
		printf("%d\n", temp);
	}
	return 0;
}

C题暴力模拟。
开一个map记录从n到1的后缀和的差,指的是,第i个位置,蓝莓和草莓的差值。
然后再从n+1的位置开始遍历。
差值的维护:
记n+1的位置蓝莓有x个,草莓y个。
一共有蓝莓n个,草莓m个。
记需要从n个里面删掉,o个蓝莓,p个草莓。
所以 n-o-x==m-y-p,移项得到,n-m=o-p+(x-y)
维护该差值即可。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
int t, n;
const int N = 2e5 + 10;
int a[N];
int sum1[N];
int sum2[N];
map<int, int>mp;
int main()
{
	t = read();
	while (t--) {
		n = read();
		upd(i, 0, 2 * n)sum1[i] = sum2[i] = 0;
		mp.clear();
		upd(i, 1, 2 * n)
		{
			a[i] = read();
			if (a[i] == 1)
			{
				sum1[i] = sum1[i - 1] + 1;
				sum2[i] = sum2[i-1];
			}
			else
			{
				sum2[i] = sum2[i - 1] + 1;
				sum1[i] = sum1[i-1];
			}
		}
		int dis = sum2[2 * n] - sum1[2 * n];
		if (dis == 0)
		{
			printf("%d\n", 0); continue;
		}
		dwd(i, n, 1)
		{
			int temp = sum1[n] - sum1[i - 1];
			int temp2 = sum2[n] - sum2[i - 1];
			temp2 -= temp;
			//printf("%d ", temp2);
			if (!mp[temp2])
			{
				mp[temp2] = i;
			}
		}
		//cout << endl;
		mp[0] = n + 1;
		int ans = inf;
		if (mp.find(dis)!=mp.end())
		{
			ans = n-(*mp.find(dis)).second+1;
		}
		upd(i, n + 1, 2 * n)
		{
			int temp = sum1[i] - sum1[n];
			int temp2 = sum2[i] - sum2[n];
			temp2 -= temp;
			temp2 = dis - temp2;
			//printf("%d ", temp2);
			if (mp.find(temp2) != mp.end())
			{
				int k = (*mp.find(temp2)).second;
				ans = min(ans, i - k + 1);
			}
		}
		//cout << endl;
 
		printf("%d\n", ans);
	}
	return 0;
}

D题
暴力and并查集
首先偏序问题,肯定排序解决一维,达到降维的目的。
我们按照线段的左端点排序。考虑右端点。
我们维护一个set,储存前i-1个的右端点。当前第i个,因为左端点已经被排序,只用考虑右端点,看是否大于set的里面的右端点,有的话加入并查集。
为了使得左端小于右端点,我们将所有右端点小于左端点的全部删掉,动态维护set。(感觉好套路。。cf出了多少道这样的题目了)
最后时间复杂度,虽然看似n^2,但其实我们因为是要建立一棵树,所以并查集不可能添加n-1次以上操作,所以复杂度就是on。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 5e5 + 10;
vector<pir>vec;
set<pir> s;
int n;
int pr[N];
int height[N];
void init()
{
	upd(i, 0, n)pr[i] = i, height[i] = 1;
}
int find_pr(int x)
{
	return pr[x] == x ?x: pr[x] = find_pr(pr[x]);
}
bool unit(int x,int y)
{
	x = find_pr(x);
	y = find_pr(y);
	if (x == y)return false;
	if (height[x] < height[y])swap(x, y);
	pr[y] = x;
	height[x] += height[y];
	return true;
}
int main()
{
	n = read();
	up(i, 0, n)
	{
		int x, y;
		x = read(), y = read();
		vec.push_back(make_pair(x, y));
	}
	init();
	sort(vec.begin(), vec.end());
	int cnt = 0;
	bool flag = 0;
	up(i, 0, n)
	{
		while (!s.empty() && s.begin()->first < vec[i].first)s.erase(s.begin());
		for (auto k : s)
		{
			if (k.first > vec[i].second)break;
			if(unit(k.second, i+1))
				cnt++;
			else flag = 1;
		}
		if (cnt > n - 1) {
			flag = 1;
		}
		if (flag == 1)break;
		s.insert(make_pair(vec[i].second,i + 1));
	}
	if (cnt != n - 1)flag = 1;
	int sum = 0;
	upd(i, 1, n)
	{
		if (pr[i] == i)sum++;
	}
	if (sum != 1)flag = 1;
	if (flag)printf("NO\n");
	else printf("YES\n");
	return 0;
}

E题:赛后补出,感觉这个构造很漂亮啊。
构造:
针对一个点u,令lf=tot,顺序遍历他的邻接子节点,邻接子节点lf=tot++,
在反向dfs他的邻接子节点即可。
这样就能保证,子节点全部和他相交,精髓在反向遍历,这样他的子节点,一定不相交,并且相容。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 5e5 + 10;
int n;
map<int, int>lf,rt;
vector<int>vec[N];
int tot = 1;
void dfs(int u, int fa)
{
	for (auto k : vec[u])
	{
		if (k == fa)continue;
		lf[k] = tot++;
	}
	rt[u] = tot++;
	vector<int>temp(vec[u]);
	reverse(temp.begin(), temp.end());
	for (auto k : temp)
	{
		if (k == fa)continue;
		dfs(k, u);
	}
}
int main()
{
	n = read();
	int u, v;
	up(i, 0, n - 1)
	{
		u = read(), v = read();
		vec[u].push_back(v);
		vec[v].push_back(u);
	}
	lf[1] = tot++;
	dfs(1, 0);
	upd(i, 1, n)
	{
		printf("%d %d\n", lf[i], rt[i]);
	}
	return 0;
}
posted @ 2019-12-21 19:05  LORDXX  阅读(172)  评论(0编辑  收藏  举报