CR 950 (Div. 3)

前言

        第一次打div 3,本来想来刷刷rating,结果没想到翻车了。。。

A. Problem Generator

        简单暴力拼手速,因为太紧张第一发交上去居然WA了,第六分钟AC。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;

int T,n,m,a[100],ans;
char s[100];

int main()
{
	scanf("%d",&T);
	while (T --)
	{
		scanf("%d%d",&n,&m),ans = 0;
		cin >> s;
		for (int i = 0;i <= 6;++ i) a[i] = 0;
		for (int i = 0;i < n;++ i) ++ a[s[i] - 'A'];
		for (int i = 0;i <= 6;++ i)
			if(a[i] < m) ans += m - a[i];
		printf("%d\n",ans);
	}
	return 0;
}

B. Choosing Cubes

        简单暴力拼手速,第11分钟AC。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;

int T,n,f,k,a[105];

int cmp(int x,int y) { return x > y ; }

int main()
{
	scanf("%d",&T);
	while (T --)
	{
		memset(a,0,sizeof a);
		scanf("%d%d%d",&n,&f,&k);
		for (int i = 1;i <= n;++ i) scanf("%d",&a[i]);
		int tmp = a[f];
		sort(a + 1,a + n + 1,cmp);
		if(a[k] > tmp) printf("NO\n");
		else if(a[k] == tmp && a[k + 1] == tmp) printf("MAYBE\n");
		else printf("Yes\n");
	}
	return 0;
}

C. Sofia and the Lost Operations

        因为后面的会覆盖前面的,于是从后往前处理,注意细节,又WA了两次,第51分钟AC。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<map>
using namespace std;

#define N 200005

int T,n,a[N],b[N],d[N],m,tot;

map<int,int> t;
map<int,int> h;

int main()
{
	scanf("%d",&T);
	while (T --)
	{
		scanf("%d",&n),tot = 0;
		for (int i = 1;i <= n;++ i) scanf("%d",&a[i]);
		for (int i = 1;i <= n;++ i) scanf("%d",&b[i]);
		for (int i = 1;i <= n;++ i)
			if(a[i] != b[i]) ++ t[b[i]],++ tot;
			else h[b[i]] = 1;
		scanf("%d",&m);
		for (int i = 1;i <= m;++ i) scanf("%d",&d[i]);
		int flag = 0;
		for (int i = m;i >= 1;-- i)
		{
			if(t[d[i]]) -- t[d[i]],-- tot,flag = 1,h[d[i]] = 1;
			else if(!h[d[i]] && !flag)
			{
				flag = 2;
				break;
			}
			else if(h[d[i]]) flag = 1;
		}
		if(flag == 2 || tot) printf("NO\n");
		else printf("YES\n");
		for (int i = 1;i <= m;++ i) h[d[i]] = t[d[i]] = 0;
		for (int i = 1;i <= n;++ i) h[b[i]] = t[b[i]] = 0;
	}
	return 0;
}

D. GCD-sequence

        简单分类讨论,比赛时因为少考虑了一种情况,一直卡在这题,后面摆烂了。。。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;

#define N 200005

int T,n,a[N],b[N];

int gcd(int x,int y) { return !(x % y) ? y : gcd(y,x % y) ; }

int main()
{
	scanf("%d",&T);
	while (T --)
	{
		scanf("%d",&n);
		for (int i = 1;i <= n;++ i) scanf("%d",&a[i]);
		for (int i = 1;i < n;++ i) b[i] = gcd(a[i],a[i + 1]);
		b[0] = -0x3f3f3f3f,b[n] = 0x3f3f3f3f,a[0] = a[n + 1] = a[n + 2] = a[n + 3] = 0;
		int t = 0;
		int t1 = 0;
		int flag = 1;
		for (int i = 1;i <= n - 2;++ i)
			if(b[i] > b[i + 1])
			{
				if(!t) t = i,flag = 2;
				else if(!t1) t1 = i,flag = 2;
				else
				{
					flag = 0;
					break;
				}
			}
		if((!flag) || (t1 > t + 2))
		{
			printf("NO\n");
			continue;
		}
		else if(flag == 1)
		{
			printf("YES\n");
			continue;
		}
		flag = 0;
		int tmp;
		if(!t1 && (t == 1 || t == n - 2)) flag = 1;
		if(a[t - 1] && !t1)
		{
			tmp = gcd(a[t - 1],a[t + 1]);
			if(b[t - 2] <= tmp && tmp <= b[t + 1]) flag = 1;
		}
		if(a[t + 2] && t1 <= t + 1)
		{
			tmp = gcd(a[t],a[t + 2]);
			if(b[t - 1] <= tmp && tmp <= b[t + 2]) flag = 1;
		}
		if(a[t + 3])
		{
			tmp = gcd(a[t + 1],a[t + 3]);
			if(b[t] <= tmp && tmp <= b[t + 3]) flag = 1;
		}
		if(flag) printf("YES\n");
		else printf("NO\n");
	}
	return 0;
}

E. Permutation of Rows and Columns

        只要保证原来的每一行与之后的某一行的数字集合是一样的、原来的每一列与之后的某一列的数字集合是一样的就合法。

#include<cstdio>
#include<cstring>
using namespace std;

#define N 200005

int T,a[N],b[N],n,m;

int main()
{
	scanf("%d",&T);
	while (T --)
	{
		scanf("%d%d",&n,&m);
		for (int i = 1;i <= n;++ i)
			for (int j = 1,x;j <= m;++ j)
				scanf("%d",&x),a[x] = (i - 1) * m + j;
		for (int i = 1;i <= n;++ i)
			for (int j = 1;j <= m;++ j)
				scanf("%d",&b[(i - 1) * m + j]);
		int flag = 1;
		for (int i = 1;i <= n;++ i)
		{
			int r = (a[b[(i - 1) * m + 1]] - 1) / m;
			for (int j = 2;j <= m;++ j)
				if((a[b[(i - 1) * m + j]] - 1) / m != r)
				{
					flag = 0;
					break;
				}
			if(!flag) break;
		}
		for (int j = 1;j <= m;++ j)
		{
			int l = (a[b[j]] - 1) % m;
			for (int i = 2;i <= n;++ i)
				if((a[b[(i - 1) * m + j]] - 1) % m != l)
				{
					flag = 0;
					break;
				}
			if(!flag) break;
		}
		if(flag) printf("YES\n");
		else printf("NO\n");
	}
	return 0;
}

F1. Field Division (easy version)

        只要一个喷泉的“左下方”没有其他喷泉,则移除这个喷泉后总面积会增加。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

#define N 200005

int T,n,m,k,ans[N];
long long tot;

struct Node
{
	int r,c,id;
}a[N];

int cmp(Node x,Node y) { return (x.r == y.r) ? (x.c < y.c) : (x.r > y.r) ; }

int main()
{
	scanf("%d",&T);
	while (T --)
	{
		scanf("%d%d%d",&n,&m,&k),tot = 0ll;
		for (int i = 1;i <= k;++ i) scanf("%d%d",&a[i].r,&a[i].c),ans[i] = 0,a[i].id = i;
		sort(a + 1,a + k + 1,cmp);
		int ml = m + 1;
		int las = n + 1;
		for (int i = 1;i <= k;++ i)
			if(a[i].c < ml)
			{
				ans[a[i].id] = 1;
				if(las == n + 1) tot += (long long)m * (long long)(las - a[i].r - 1ll),las = a[i].r + 1;
				else tot += (long long)(ml - 1ll) * (long long)(las - a[i].r);
				las = a[i].r;
				ml = a[i].c;
			}
		tot += (long long)las * (long long)(ml - 1ll);
		printf("%lld\n",tot);
		for (int i = 1;i <= k;++ i) printf("%d ",ans[i]);
		printf("\n");
	}
	return 0;
}

F2. Field Division (hard version)

        在 easy version 的基础上记录每个喷泉移除后增加的面积即可,其实也没有多难。。。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

#define N 200005

int T,n,m,k;
long long tot,ans[N];

struct Node
{
	int r,c,id;
}a[N];

int cmp(Node x,Node y) { return (x.r == y.r) ? (x.c < y.c) : (x.r > y.r) ; }

int min(int x,int y) { return x < y ? x : y ; }

int main()
{
	scanf("%d",&T);
	while (T --)
	{
		scanf("%d%d%d",&n,&m,&k),tot = 0ll;
		for (int i = 1;i <= k;++ i) scanf("%d%d",&a[i].r,&a[i].c),ans[i] = 0,a[i].id = i;
		sort(a + 1,a + k + 1,cmp);
		int ml = m + 1;
		int las = n + 1;
		int flag = 0;
		for (int i = 1;i <= k;++ i)
		{
			if(a[i].c <= ml) flag = i;
			if(a[i].c < ml)
			{
				ans[a[i].id] = 1;
				if(las == n + 1) tot += (long long)m * (long long)(las - a[i].r - 1ll),las = a[i].r + 1;
				else tot += (long long)(ml - 1ll) * (long long)(las - a[i].r);
				las = a[i].r;
				ml = a[i].c;
			}
		}
		tot += (long long)las * (long long)(ml - 1ll);
		printf("%lld\n",tot);
		int i = 1;
		ml = m + 1;
		int now;
		int f = 0;
		while (i <= k)
		{
			if(ans[a[i].id])
			{
				int tmp = i + 1;
				ans[a[i].id] = 0;
				now = (a[i].r == a[i + 1].r && i < k) ? (min(ml,a[i + 1].c) - a[i].c) : (ml - a[i].c);
				las = a[i].r;
				if(a[i].r == 1)
				{
					ans[a[i].id] = now * a[i].r;
					break;
				}
				if(i == flag) a[++ k].r = 0,a[k].c = 1,a[k].id = ans[0] = 0,f = 1;
				int mn = now;
				while (tmp <= k)
				{
					if(a[tmp].r == a[tmp - 1].r)
					{
						ml = min(ml,a[tmp].c);
						++ tmp;
						continue;
					}
					ans[a[i].id] += (long long)now * (long long)(las - a[tmp].r);
					las = a[tmp].r;
					if(ans[a[tmp].id]) break;
					ml = min(ml,a[tmp].c);
					mn = now;
					now = ml - a[i].c;
					++ tmp;
				}
				ml = min(ml,a[i].c);
				i = tmp;
			}
			else ml = min(ml,a[i].c),++ i;
		}
		for (int i = 1;i <= k - f;++ i) printf("%lld ",ans[i]);
		printf("\n");
	}
	return 0;
}

G. Yasya and the Mysterious Tree

        记 di 为节点 i 到根节点路径上的异或和,那么两点间路径上的异或和即为 dv \oplus du 。

        对于第1类询问,我们只需用一个 tot 储存所有1类询问的异或和即可。

        对于第2类询问,我们首先可以发现的是,边数为偶数的路径上的异或和是不会因为1类询问发生改变的,于是就可以分奇偶两种情况讨论:

        1. 两个点 u,v 的深度的奇偶性相同,则贡献为 dv \oplus x \oplus du 。

        2. 两个点 u,v 的深度的奇偶性不同,则贡献为 dv \oplus x \oplus tot \oplus du 。

        我们用两个trie存储所有的di,分别存奇数深度的点和偶数深度的点,然后用trie查询即可。

        注意不能连自环,特判一下。

        时间复杂度:O(n log val)

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
 
#define N 200005
 
int T,n,m,st[N],cnt,d[N],od[N],tr1[N * 30][2],tr2[N * 30][2],n1,n2,tot,ans,c1[N * 30],c2[N * 30],b1[N * 30],b2[N * 30];
 
struct Edge
{
	int next,to,val;
}ed[N << 1];
 
int max(int x,int y) { return x > y ? x : y ; }
 
void add(int u,int v,int w)
{
	ed[++ cnt].next = st[u];
	ed[cnt].to = v;
	ed[cnt].val = w;
	st[u] = cnt;
	return;
}
 
void dfs(int x,int fa,int dep)
{
	od[x] = dep & 1;
	for (int i = st[x]; ~i ;i = ed[i].next)
	{
		int rec = ed[i].to;
		if(rec == fa) continue;
		d[rec] = d[x] ^ ed[i].val;
		dfs(rec,x,dep + 1);
	}
	return;
}
 
void add1(int x,int y)
{
	int now = 0;
	for (int i = 29;i >= 0;-- i)
	{
		int tmp = (x >> i) & 1;
		if(tr1[now][tmp]) now = tr1[now][tmp],++ c1[now];
		else tr1[now][tmp] = ++ n1,now = n1,c1[now] = 1;
		b1[now] = y;
	}
	return;
}
 
void add2(int x,int y)
{
	int now = 0;
	for (int i = 29;i >= 0;-- i)
	{
		int tmp = (x >> i) & 1;
		if(tr2[now][tmp]) now = tr2[now][tmp],++ c2[now];
		else tr2[now][tmp] = ++ n2,now = n2,c2[now] = 1;
		b2[now] = y;
	}
	return;
}
 
int ask1(int x,int y)
{
	int t = 0;
	int now = 0;
	for (int i = 29;i >= 0;-- i)
	{
		int tmp = (x >> i) & 1;
		if((!tr1[now][tmp ^ 1]) || (c1[tr1[now][tmp ^ 1]] == 1 && b1[tr1[now][tmp ^ 1]] == y))
			now = tr1[now][tmp];
		else t += 1 << i,now = tr1[now][tmp ^ 1];
	}
	return t;
}
 
int ask2(int x,int y)
{
	int t = 0;
	int now = 0;
	for (int i = 29;i >= 0;-- i)
	{
		int tmp = (x >> i) & 1;
		if((!tr2[now][tmp ^ 1]) || (c2[tr2[now][tmp ^ 1]] == 1 && b2[tr2[now][tmp ^ 1]] == y))
			now = tr2[now][tmp];
		else t += 1 << i,now = tr2[now][tmp ^ 1];
	}
	return t;
}
 
int main()
{
	scanf("%d",&T);
	while (T --)
	{
		scanf("%d%d",&n,&m),cnt = n1 = n2 = tot = 0;
		for (int i = 1;i <= n;++ i) st[i] = -1,d[i] = od[i] = 0;
		for (int i = 1,u,v,w;i < n;++ i) scanf("%d%d%d",&u,&v,&w),add(u,v,w),add(v,u,w);
		dfs(1,0,0);
		for (int i = 1;i <= n;++ i)
			if(od[i] & 1) add1(d[i],i);
			else add2(d[i],i);
		for (int i = 1,v,w;i <= m;++ i)
		{
			char s;
			cin >> s;
			if(s == '^') scanf("%d",&w),tot ^= w;
			else
			{
				scanf("%d%d",&v,&w),ans = 0;
				if(od[v])
				{
					ans = max(ans,ask1(d[v] ^ w,v));
					ans = max(ans,ask2(d[v] ^ w ^ tot,v));
				}
				else
				{
					ans = max(ans,ask1(d[v] ^ w ^ tot,v));
					ans = max(ans,ask2(d[v] ^ w,v));
				}
				printf("%d\n",ans);
			}
		}
		for (int i = 0;i <= n1;++ i) tr1[i][0] = tr1[i][1] = c1[i] = b1[i] = 0;
		for (int i = 0;i <= n2;++ i) tr2[i][0] = tr2[i][1] = c2[i] = b2[i] = 0;
	}
	return 0;
}

总结

        做简单题的时候往往容易出错,注意细节问题,比如分类讨论、用trie时对空间的计算等等。

  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值