Educational Codeforces Round 23 A-F

感觉这种比赛就是拼手速啊QwQ

A.Treasure Hunt

题目大意:平面直角坐标系中给定起点和终点,每次可以从(a,b)走向(a+x,b+y),(a-x,b-y),(a+x,b-y),(a-x,b+y)这四个点。

问从起点能否到达终点。

要求O(1)做法。

题解:这个第一遍提交还WA了QwQ。

首先如果这个是在一维直线上的,那么只要判断|x1-x2|是不是x的倍数即可。

在二维的情况中,不仅要判断两个是否同时满足,还要保证|x1-x2|/x和|y1-y2|/y是不是同奇偶。


B.Makes And The Product

题目大意:给定一列数,找到三个下标不同的数,使得她们的乘积最小,问有多少种方案。

要求O(n)做法。

题解:排序后分类讨论即可。讨论结果和代码差不多。


C.Really Big Numbers

题目大意:给定n和s,问在不大于n的正整数中,满足这个数减去各位数字之和不小于s的数字有多少。

n,s<=1e18

题解:假设这个数是x,各位数字之和为d,那么x最多是18位数,每位最大是9,所以d<=18*9=162。

也就是对于>=s+162的数字x是一定满足条件的。

又要求x-d>=s所以x>=s+d>=s所以小于s的所有数字是不满足条件的。

因此判断一下中间那些数即可。


D. Imbalanced Array

题目大意:给定一列数,每个区间的值为这个区间的最大值减去最小值。求所有区间的值的和。

要求O(n)做法。

题解:首先那个差是无关紧要的。

问题变为求所有区间的最大/小值的和。

那这个东西显然是可以用单调栈来维护的。


E.Choosing The Commander

题目大意:维护一个数据结构,实现三种操作:

1.加入一个数x。

2.把x删除。

3.给定两个数a,b,问已经加入并且没有被删除的x中有多少个x满足x^a小于b。(^是异或)

q<=1e5,a,b,x<=1e8。

题解:一看到异或果断想trie。然后前两个操作就变成了修改链值,暴力即可。

第三个操作,分a的第d位是0还是1讨论,并保存一个延trie上当前路径走下来到这个节点的值是多少(记作v)。

举例来讲,如果a的第d位是0,那么第d-1位走0是一定可行的。这个时候如果b的第d-1位是1,那么说明只要第d-1位为0那么接下来再怎么走都可以,直接返回下一个结点的权值即可。(因为是从高位向低位考虑的)

同时如果第d-1位选择走1,那就要保证b的第d-1位是1(或者也可以认为把v的第d-1位置为1后小于b)。

a的第d位是1同理,详见代码。

复杂度未知。(可能是玄学)


F. MEX Queries

题目大意:维护数据结构,实现4种操作:

1.将区间[L,R]全部赋为1.

2.将区间[L,R]全部赋为0.

3.将区间[L,R]全部取反.

4.询问当前区间的mex。mex即当前序列1,2,....,中第一个为0的数。

初始全部为0。

L<=R<=1e18

要求O(mlgm)的做法。

题解:首先L,R这么大没有意义离散化即可。

这样就用线段树暴力维护即可。

注意有两个标记(取反和赋值)注意考虑维护的先后顺序。

两个坑点一个是你不能只把L,R离散化,还要将L+1和R+1离散化。

这样可以避免形如1 1 2; 1 4 5; 4 ;这样的操作序列输出错误的答案4。

另一个是就算数据没有1也要把1离散化了。

这样避免所有L都>1时会输出奇怪的数字。

还有就是不要忘了用long long读入。


代码们:

A.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int main()
{
	int x1,y1,x2,y2;scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
	int x,y;scanf("%d%d",&x,&y);
	int px=abs(x1-x2),py=abs(y1-y2);
	if(px%x==0&&py%y==0&&abs(px/x-py/y)%2==0) printf("YES\n");
	else printf("NO\n");return 0;
}

B.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 100010
#define lint long long
using namespace std;
int a[MAXN];
int main()
{
	int n;scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	sort(a+1,a+n+1);
	if(a[1]==a[3])
	{
		int cnt=0;
		for(int i=1;i<=n;i++)
			if(a[i]==a[1]) cnt++;
		printf("%I64d\n",(lint)cnt*(cnt-1)/2*(cnt-2)/3);
		return 0;
	}
	if(a[1]<a[2])
	{
		int cnt2=0,cnt3=0;
		for(int i=1;i<=n;i++)
		{
			if(a[i]==a[2]) cnt2++;
			if(a[i]==a[3]) cnt3++;
		}
		if(a[2]==a[3]) printf("%I64d\n",(lint)cnt2*(cnt2-1)/2);
		else printf("%d\n",cnt3);
		return 0;
	}
	if(a[1]==a[2])
	{
		int cnt=0;
		for(int i=1;i<=n;i++)
			if(a[i]==a[3]) cnt++;
		printf("%d\n",cnt);
		return 0;
	}
	return 0;
}
C.
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define lint long long
using namespace std;
int a[100];
int main()
{
	lint n,s;scanf("%I64d%I64d",&n,&s);
	lint ans=max(n-s-161,0LL);
	for(lint i=min(s+161,n);i>=s;i--)
	{
		lint x=i;int len=0;
		while(x)
		{
			a[++len]=x%10;
			x/=10;
		}
		int ss=0;
		for(int j=1;j<=len;j++)
			ss+=a[j];
		if(i-ss>=s) ans++;
	}
	printf("%I64d\n",ans);
	return 0;
}

D.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#define MAXN 1000010
#define lint long long
#define INF INT_MAX
using namespace std;
stack<int> s1,s2;
lint ans1,ans2,ans;
int a[MAXN];
int main()
{
	int n;scanf("%d",&n);
	while(!s1.empty()) s1.pop();s1.push(0);
	while(!s2.empty()) s2.pop();s2.push(0);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);a[0]=0;
		while(s1.top()&&a[i]<a[s1.top()])
		{
			int t=s1.top();s1.pop();
			ans1-=(lint)a[t]*(t-s1.top());
		}
		ans1+=(lint)a[i]*(i-s1.top());s1.push(i);
		a[0]=INF;
		while(s2.top()&&a[i]>a[s2.top()])
		{
			int t=s2.top();s2.pop();
			ans2-=(lint)a[t]*(t-s2.top());
		}
		ans2+=(lint)a[i]*(i-s2.top());s2.push(i);
		ans+=ans2-ans1;
	}
	printf("%I64d\n",ans);
	return 0;
}
E.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<assert.h>
using namespace std;
struct trie{
	int s;
	trie *ch[2];
}*rt;
int maintain(trie* &rt)
{
	rt->s=0;
	if(rt->ch[0]!=NULL) rt->s+=rt->ch[0]->s;
	if(rt->ch[1]!=NULL) rt->s+=rt->ch[1]->s;
	return 0;
}
int update(trie* &rt,int p,int v,int d)
{
	if(rt==NULL)
	{
		rt=new trie;rt->s=0;
		rt->ch[0]=rt->ch[1]=NULL;
	}
	if(!d) return rt->s+=v;
	else d--;
	int g=(p&(1<<d))>>d;
	update(rt->ch[g],p,v,d);
	maintain(rt);return 0;
}
int query(trie* &rt,int p,int l,int d,int v)
{
	if(!d) return rt->s;
	else d--;
	int g=(p&(1<<d))>>d,ans=0;
	if(g==0)
	{
		if(rt->ch[0]!=NULL)
		{
			if((l&(1<<d))>>d) ans+=rt->ch[0]->s;
			else ans+=query(rt->ch[0],p,l,d,v);
		}
		if(rt->ch[1]!=NULL&&(v|(1<<d))<l)
			ans+=query(rt->ch[1],p,l,d,v|(1<<d));
	}
	else{
		if(rt->ch[0]!=NULL&&(v|(1<<d))<l)
			ans+=query(rt->ch[0],p,l,d,v|(1<<d));
		if(rt->ch[1]!=NULL)
		{
			if((l&(1<<d))>>d) ans+=rt->ch[1]->s;
			else ans+=query(rt->ch[1],p,l,d,v);
		}
	}
	return ans;
}
int main()
{
	rt=new trie;rt->s=0;
	rt->ch[0]=rt->ch[1]=NULL;
	int q;scanf("%d",&q);
	while(q--)
	{
		int opt;scanf("%d",&opt);
		if(opt==1||opt==2)
		{
			int p;scanf("%d",&p);
			if(opt==1) update(rt,p,1,28);
			else update(rt,p,-1,28);
		}
		else{
			int p,l;scanf("%d%d",&p,&l);
			printf("%d\n",query(rt,p,l,28,0));
		}
	}
	return 0;
}

F.
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define MAXQ 100010
#define lint long long
using namespace std;
struct segment{
	int s,l,r,t;
	bool revt,updt;
	segment *ch[2];
}*rt;
vector<lint> v;
lint L[MAXQ],R[MAXQ];
int OPT[MAXQ];
inline int push_up(segment* &rt)
{
	rt->s=rt->ch[0]->s+rt->ch[1]->s;
	return 0;
}
int build(segment* &rt,int l,int r)
{
	rt=new segment;
	rt->ch[0]=rt->ch[1]=NULL;
	rt->l=l;rt->r=r;
	rt->revt=false;
	rt->updt=rt->s=0;
	if(l==r) return 0;
	int mid=(l+r)>>1;
	build(rt->ch[0],l,mid);
	build(rt->ch[1],mid+1,r);
	return 0;
}
int update_tags(segment* &rt,int t)
{
	rt->t=t;
	rt->updt=true;
	rt->revt=false;
	rt->s=(rt->r-rt->l+1)*t;
	return 0;
}
int update_rev(segment* &rt)
{
	if(rt->updt)
	{
		rt->t=1-rt->t;
		rt->s=(rt->r-rt->l+1)*rt->t;
		rt->revt=false;
	}
	else{
		rt->revt=!rt->revt;
		rt->s=rt->r-rt->l+1-rt->s;
	}
	return 0;
}
int push_down(segment* &rt)
{
	if(rt->updt)
	{
		update_tags(rt->ch[0],rt->t);
		update_tags(rt->ch[1],rt->t);
	}
	if(rt->revt)
	{
		update_rev(rt->ch[0]);
		update_rev(rt->ch[1]);
	}
	rt->revt=false;
	rt->updt=false;
	rt->t=0;return 0;
}
int update(segment* &rt,int s,int t,int v)
{
	int l=rt->l,r=rt->r;
	if(s<=l&&r<=t)
	{
		rt->revt=false;
		rt->updt=true;
		rt->t=v;
		rt->s=(r-l+1)*v;
		return 0;
	}
	int mid=(l+r)>>1;
	if(rt->revt||rt->updt) push_down(rt);
	if(s<=mid) update(rt->ch[0],s,t,v);
	if(mid<t) update(rt->ch[1],s,t,v);
	push_up(rt);return 0;
}
int query(segment* &rt)
{
	int s=rt->s,l=rt->l,r=rt->r;
	if(l==r) return s?(l+1):r;
	int mid=(l+r)>>1;
	if(rt->updt||rt->revt) push_down(rt);
	if(rt->ch[0]->s==rt->ch[0]->r-rt->ch[0]->l+1) return query(rt->ch[1]);
	else return query(rt->ch[0]);
}
int reverse(segment* &rt,int s,int t)
{
	int l=rt->l,r=rt->r;
	if(s<=l&&r<=t) return update_rev(rt);
	int mid=(l+r)>>1;
	if(rt->updt||rt->revt) push_down(rt);
	if(s<=mid) reverse(rt->ch[0],s,t);
	if(mid<t) reverse(rt->ch[1],s,t);
	push_up(rt);return 0;
}
int getid(lint x)
{
	return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
int main()
{
	int q;scanf("%d",&q);
	for(int i=1;i<=q;i++)
	{
		scanf("%d%I64d%I64d",&OPT[i],&L[i],&R[i]);
		v.push_back(L[i]);v.push_back(L[i]+1);
		v.push_back(R[i]);v.push_back(R[i]+1);
	}
	v.push_back(1);
	sort(v.begin(),v.end());
	v.erase(unique(v.begin(),v.end()),v.end());
	build(rt,1,v.size());
	for(int i=1;i<=q;i++)
	{
		int l=getid(L[i]),r=getid(R[i]),opt=OPT[i];
		if(opt==1||opt==2) update(rt,l,r,opt&1);
		else reverse(rt,l,r);
		printf("%I64d\n",v[query(rt)-1]);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值