Educational Codeforces Round 6 A---E

总结

本场前三题较为简单。
D题涉及到了推公式+二分
E题dfs序+线段树
可以发现这场题目数据范围提示比较明显。 多多注意数据范围!!

A. Professor GukiZ’s Robot

int main()
{
//	int T;
//	scanf("%d", &T);
//	while(T --)
//	{
		ll x1, y1, x2, y2;
		scanf("%lld %lld %lld %lld", &x1, &y1, &x2, &y2);
		ll temp1 = abs(x1 - x2), temp2 = abs(y1 - y2);
		printf("%lld\n", min(temp1, temp2) + temp1 - min(temp1, temp2) + temp2 - min(temp1, temp2));
//	}
	return 0;
}

B. Grandfather Dovlet’s calculator

int a[] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};
ll cal(int now)
{
	ll sum = 0;
	while(now)
	{
		int dig = now % 10;
		sum += a[dig];
		now /= 10;
	}
	return sum;
}
int main()
{
	ll a ,b;
	scanf("%lld %lld", &a, &b);
	ll res = 0;
	for(int i = a ; i <= b ; i ++)
	{
		res += cal(i);
	}
	printf("%lld\n",res);
	return 0;
}

C. Pearls in a Row

ll a[maxn];
map <ll, int> mp;
int main()
{
	int n;
	scanf("%d", &n);
	for(int i = 1 ; i <= n ; i ++)
	scanf("%lld", &a[i]);
	vector <PII> alls;
	int l = -1, r;
	for(int i = 1 ; i <= n ; i ++)
	{
		mp[a[i]] ++;
		if(l == -1)
		l = i;
		else if(mp[a[i]] == 2)
		{
			r = i;
			alls.push_back({l, r});
			for(int j = l ; j <= r ; j ++)
			mp[a[j]] --;	
			l = -1;
		}
	}
	if(alls.empty())
	printf("-1\n");
	else
	{
		printf("%d\n", alls.size());
		if(alls[alls.size() - 1].second != n)
		alls[alls.size() - 1].second = n;
		for(auto t : alls)
		printf("%d %d\n", t.first, t.second);
	}
	return 0;
}

D. Professor GukiZ and Two Arrays

题意:

给定两个数组A,B,问最多经过两次交换AB数组中任意元素,使得的差值要尽量小并输出具体方案。

思路:

一开始没有想到分类讨论。感觉是DP。
但是DP了半天,没有de出来。
赛后发现是分类讨论。想想的确也对。毕竟要求最多经过两次交换。!!!!
数据范围提示非常明显啊!!!!
K = 0时, ans = abs(suma - sumb)
K = 1时, ans = abs(suma - sumb - 2 * (a[i] - b[j])) (可预处理出来, 毕竟n <= 2e3)
K = 2时, ans = abs(suma - sumb - 2 * (a[i] - b[j]) - 2 * (a[k] - b[t]))
那么可以发现只剩下最后一种情况。
可以发现当枚举k、t时。abs(suma - sumb - 2 * (a[k] - b[t]))为定值,设为s。
只有2 * (a[i] - b[j])不定。
此外可以发现i、j、k、t各不相同。
考虑二分,可以二分出 2 * (a[i] - b[j]) <= s的最后一个数。
二分出2 * (a[i] - b[j]) >= s的第一个数。
假设二分到的值,已经为k、t重复了。那么直接对应往后/往前移动就好了

struct note{ // 
	int l;
	int r;
	ll w;
}A[maxn];
ll a[maxn], b[maxn];
bool cmp(note A, note B)
{
	return A.w < B.w;
}
int main()
{
	int n;
	scanf("%d", &n);
	ll suma = 0, sumb = 0;
	for(int i = 1 ; i <= n ; i ++)
	scanf("%lld", &a[i]), suma += a[i];
	int m;
	scanf("%d", &m);
	for(int i = 1 ; i <= m ; i ++)
	scanf("%lld", &b[i]), sumb += b[i];
	vector <PII> ans;
	ll res = abs(suma - sumb);
	int cnt = 0;
	for(int i = 1 ; i <= n ; i ++)
	{
		for(int j = 1 ; j <= m ; j ++)
		{
			A[++ cnt] = {i, j, 2ll * (a[i] - b[j])};
			if(res > abs(suma - sumb - 2ll * (a[i] - b[j])))
			{
				vector <PII> temp;
				res = abs(suma - sumb - 2ll * (a[i] - b[j]));
				temp.push_back({i, j});
				ans = temp;
			}
		}
	}
	sort(A + 1, A + m * n + 1, cmp);
	for(int k = 1 ; k <= n ; k ++)
	{
		for(int t = 1 ; t <= m ; t ++)
		{
			ll temp = suma - sumb - 2ll * (a[k] - b[t]);	
			int l = 1, r = m * n;
			while(l < r) 
			{
				int mid = (l + r) >> 1;
				if(A[mid].w >= temp) r = mid;
				else l = mid + 1;
			}	
			if(A[l].w >= temp)
			{
				while(A[l].l == k || A[l].r == t)
				{
					l ++;
				}
				if(l <= m * n)
				{
					if(res > abs(temp - A[l].w))
					{
						res = abs(temp - A[l].w);
						vector <PII> c; 
						c.push_back({A[l].l, A[l].r});
						c.push_back({k, t});
						ans = c;
					}
				}
			}
			l = 1, r = m * n;
			while(l < r)
			{
				int mid = (l + r + 1) >> 1;
				if(A[mid].w <= temp) l = mid;
				else r = mid - 1;
			}
			if(A[l].w <= temp)
			{
				while(A[l].l == k || A[l].r == t)
				{
					l --;
				}
				if(l >= 1)
				{
					if(res > abs(temp - A[l].w))
					{
						res = abs(temp - A[l].w);
						vector <PII> c;
						c.push_back({A[l].l, A[l].r});
						c.push_back({k, t});
						ans = c;
					}
				}
			}
		}
	}
	printf("%lld\n",res);
	printf("%d\n", ans.size());
	for(auto t : ans)
	printf("%d %d\n", t.first, t.second);
	return 0;
}	

E. New Year Tree

题意:

给定n个顶点,n - 1条边。每个顶点都有一个颜色。
m个查询。
query1:v c :把v所在的子树中的点全部染色为颜色c
query2: v : 查询此时v所在的子树中颜色的种类数

思路:

首先发现存在修改操纵。不能用近段时间学的Dsu on tree 且 颜色数量 <= 60。
存在区间修改、区间查询。
由于颜色数量少,直接开longlong用二进制表示即可(区间合并用 | 运算符即可)。

code:

ll c[maxn];
int h[maxn], ne[maxn * 2], e[maxn * 2], idx, in[maxn], out[maxn], tim, id[maxn];
void add(int u, int v)
{
	e[idx] = v;
	ne[idx] = h[u];
	h[u] = idx ++;	
}  
void dfs(int sta, int fa)
{
	in[sta] = ++ tim;
	id[tim] = sta;
	for(int i = h[sta] ; i != -1 ; i = ne[i])
	{
		int son = e[i];
		if(son == fa) continue;
		dfs(son, sta);
	}
	out[sta] = tim;
}
struct note{
	int l;
	int r;	
	ll lazy;
	ll w;
	int mid()
	{
		return (l + r) >> 1;
	}
}tre[maxn << 2];
void pushup(int rt)
{
	tre[rt].w = tre[rt * 2].w | tre[rt * 2 + 1].w;
}
void pushdown(int rt)
{
	if(tre[rt].lazy > 0)
	{
		tre[rt * 2].w = 1ll << tre[rt].lazy;
		tre[rt * 2 + 1].w = 1ll << tre[rt].lazy;
		tre[rt * 2].lazy = tre[rt].lazy;
		tre[rt * 2 + 1].lazy = tre[rt].lazy;
		tre[rt].lazy = 0;
	}
 
}
void build(int rt, int l, int r)
{
	tre[rt] = {l, r, 0ll};
	if(tre[rt].l == tre[rt].r) //叶子 
	{
		tre[rt].w = 1ll << c[id[tre[rt].l]];
		return ;
	}
	int mid = tre[rt].mid();
	build(rt * 2, l, mid), build(rt * 2 + 1, mid + 1, r);
	pushup(rt);
}
void modify(int rt, int l, int r, ll t) //区间修改 
{
	if(tre[rt].l == l && tre[rt].r == r)
	{
		tre[rt].w = 1ll << t;
		tre[rt].lazy = t;
//		printf("ffff %d %lld %lld\n", id[tre[rt].l], t, tre[rt].w);
		return ;
	}
	pushdown(rt);
	int mid = tre[rt].mid();
	if(l > mid) //右子树
	modify(rt * 2 + 1, l, r, t);
	else if(r <= mid)
	modify(rt * 2, l, r, t);
	else
	{
		modify(rt * 2, l, mid, t);
		modify(rt * 2 + 1, mid + 1, r, t);	
	} 
	pushup(rt); 
}
note query(int rt, int l, int r)
{
	if(tre[rt].l == l && tre[rt].r == r)
	{
		return tre[rt];
	}
	pushdown(rt);
	int mid = tre[rt].mid();
	if(r <= mid)
	return query(rt * 2, l, r);
	else if(l > mid)
	return query(rt * 2 + 1, l, r);
	else
	{
		note temp, temp1, temp2;
		temp1 = query(rt * 2, l, mid), temp2 = query(rt * 2 + 1, mid + 1 , r);
		temp.w = temp1.w | temp2.w;
		return temp;
	}
}
int main()//区间修改 
{
	int n, m;
	scanf("%d %d", &n, &m);
	for(int i = 1 ; i <= n ; i ++)
	scanf("%lld", &c[i]);
	memset(h, -1 , sizeof(h)), idx = 0;
	for(int i = 1 ; i < n ; i ++)
	{
		int u, v;
		scanf("%d %d", &u, &v);
		add(u, v), add(v, u);
	}
	dfs(1, -1);
	build(1, 1, n);
	while(m --)
	{
		int t;
		scanf("%d", &t);
		if(t == 1)
		{
			int v;
			ll d;
			scanf("%d %lld", &v, &d);
			modify(1, in[v], out[v], d);
//			printf("f : %lld\n", query(1, in[v], out[v]).w);
		}
		else
		{
			int v;
			scanf("%d", &v);	
			ll temp = query(1, in[v], out[v]).w;
			int cnt = 0;
			for(ll i = 62 ; i >= 0 ; i --)
			{
				if(temp >> i & 1)	
				cnt ++;
			}		
			printf("%d\n", cnt);
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值