CF1851 A-G

发布时间 2023-07-28 18:07:39作者: Simex

link

A

非常简单的比较大小问题

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<ctime>
#include<bitset>
using namespace std;
int t;
int n,m,k,H;
int a[100];
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d%d%d%d",&n,&m,&k,&H);
		int ans=0;
		for(int i=1;i<=n;++i){
			scanf("%d",&a[i]);
			int d=abs(a[i]-H);
			if(d%k==0&&(d/k)<=m-1&&d!=0){
				//cout<<a[i]<<endl;
				ans++;
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}

B

把奇数跟偶数分别排列就行

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<ctime>
#include<bitset>
#define int long long
using namespace std;
int t;
int n;
int p[2];
int rec[200005];
int o[2][200005];
long long a[200005];
signed main(){
	scanf("%lld",&t);
	while(t--){
		scanf("%lld",&n);
		p[0]=p[1]=0;
		for(int i=1;i<=n;++i){
			scanf("%lld",&a[i]);
			rec[i]=a[i]%2;
			p[a[i]%2]++;
			o[a[i]%2][p[a[i]%2]]=a[i];
		}
		sort(o[0]+1,o[0]+1+p[0]);
		sort(o[1]+1,o[1]+1+p[1]);
		int p1=0,p2=0;
		for(int i=1;i<=n;++i){
			if(rec[i]==0){
				p1++;
				a[i]=o[0][p1];
			}else{
				p2++;
				a[i]=o[1][p2];
			}
		}
		int f=0;
		for(int i=1;i<n;++i){
			if(a[i+1]<a[i]){
				f=1;
				break;
			}
		}
		if(f){
			cout<<"NO\n";
		}else{
			cout<<"YES\n";
		}
	}
	return 0;
}

C

分类讨论一下第一个和最后一个颜色一不一样就行。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<ctime>
#include<bitset>
using namespace std;
int t;
int n,k;
int a[200005];
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&k);
		for(int i=1;i<=n;++i){
			scanf("%d",&a[i]);
		}
		int f=0;
		if(a[1]==a[n]){
			int cnt=0;
			for(int i=1;i<=n;++i){
				if(a[i]==a[1]) cnt++;
			}
			if(cnt>=k) f=1;
		}else{
			int d1=1,d2=n;
			int cnt1=0;
			int cnt2=0;
			for(d1=1;d1<=n;++d1){
				if(a[d1]==a[1]) cnt1++;
				if(cnt1==k) break;
			}
			for(d2=n;d2>=1;--d2){
				if(a[d2]==a[n]) cnt2++;
				if(cnt2==k) break;
			}
			if(cnt1==k&&cnt2==k&&d1<=d2){
				f=1;
			}
		}
		if(f){
			cout<<"YES\n";
		}else{
			cout<<"NO\n";
		}
	}
	return 0;
}

D

我觉得这个应该和E换换位置,比E难想点,比E难写点。
我们考虑一下我们用我们得到的前缀和数组回还原出来个什么东西。
如果我们得到的前缀和数组是正确的,那么只有两种可能,还原出来的数组包括1n中的n-1个或者是包括1n中的n-2个,然后包括一个和这n-2个数重复的数或者一个超过n的数
然后我们只要检查1-n中丢失的那两个数能不能加起来和为那个异常数字就可以了。
前一种情况意味着丢失了最后一个前缀和,后面的情况意味着丢失了前面的前缀和,而这样就相当于把原数组的相邻两个数的和代替了这两个数.

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<ctime>
#include<bitset>
#define int long long
using namespace std;
int t;
int n;
long long a[200005];
map<long long,int> m;
int pp[200005];
signed main(){
	scanf("%lld",&t);
	while(t--){
		scanf("%lld",&n);
		int er=0;
		int err=0;
		for(int i=1;i<n;++i){
			scanf("%lld",&a[i]);
		}
		int f=0;
		m.clear();
		for(int i=1;i<n;++i){
			long long d=a[i]-a[i-1];
			if(m[d]==1||d>n){
				if(er==1){
					f=-1;
					break;
				}
				er++;
				err=d;
			}
			m[d]=1;
		}
		if(f==-1){
			cout<<"NO"<<endl;
			continue;
		}
		if(er==0){
			cout<<"YES"<<endl;
			continue;
		}
		int p=0;
		
		for(int i=1;i<=n;++i){
			if(m[i]!=1){
				p++;
				pp[p]=i;
			}
		}
		if(p!=2) f=0;else{
			if(pp[1]+pp[2]==err) f=1;
			else f=0;
		}
		if(f){
			cout<<"YES"<<endl;
		}else{
			cout<<"NO"<<endl;
		}
	}
	return 0;
}

E E. Nastya and Potions

有向图BFS就可以了。
就是在最终确定某个物品的价值的时候确定一下它是否免费以及是不是直接买更便宜。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define int long long
using namespace std;
int n,k;
int t;
long long c[200005];
int fre[200005];
queue<int> q;
int pri[200005];
int head[200005];
int p;
int ans[200005];
struct edge{
	int to;
	int ne;
}ed[200005];
void add(int f,int to){
	p++;
	ed[p].to=to;
	ed[p].ne=head[f];
	head[f]=p;
}
int x,y;
int du[200005];
signed main(){
	scanf("%lld",&t);
	while(t--){
		scanf("%lld%lld",&n,&k);;
		for(int i=1;i<=n;++i){
			scanf("%lld",&c[i]);
		}
		p=0;
		memset(ans,0,sizeof(ans));
		memset(head,0,sizeof(head));
		memset(pri,0,sizeof(pri));
		for(int i=1;i<=k;++i){
			scanf("%lld",&x);
			pri[x]=1;;
		}
		for(int i=1;i<=n;++i){
			scanf("%lld",&x);
			du[i]=x;
			if(x==0){
				ans[i]=pri[i]==1?0:c[i];
				q.push(i);
			}else{
				for(int j=1;j<=x;++j){
					scanf("%lld",&y);
					add(y,i);
				}
			}
		}
		while(!q.empty()){
			x=q.front();
			q.pop();
			for(int i=head[x];i;i=ed[i].ne){
				y=ed[i].to;
				ans[y]+=ans[x];
				du[y]--;
				if(du[y]==0){
					q.push(y);
					if(pri[y]) ans[y]=0;
					else ans[y]=min(ans[y],c[y]);
				}
			}
		}
		for(int i=1;i<=n;++i){
			cout<<ans[i]<<" ";
		}
		cout<<endl;
	}
	return 0;
}

F F. Lisa and the Martians

整个题面都在暗示要按照二进制位处理。
我们考虑一下对于结果的某一位,怎样这一位才会是
就且仅就是当\(a_i\)\(a_j\)的这一位相同就可以了
那么我们就要考虑让相同的位为1的情况下得到的数尽可能大。
显然可以考虑排序后比较相邻异或值,越小得到的答案越大。
最后构造x就可以了。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<ctime>
#include<bitset>
using namespace std;
int t;
struct el{
	long long v;
	int id;
}e[200005];
int n;
long long k;
bool cmp(el x,el y){
	return x.v<y.v;
}
int x;
int y;
long long ans;
long long xx,yy;
int main(){
	scanf("%d",&t);
	while(t--){
		ans=1<<30;
		scanf("%d%lld",&n,&k);
		for(int i=1;i<=n;++i){
			scanf("%lld",&e[i].v);
			e[i].id=i;
		}
		sort(e+1,e+1+n,cmp);
		for(int i=1;i<n;++i){
			long long d=e[i].v^e[i+1].v;
			if(d<ans){
				x=e[i].id;
				xx=e[i].v;
				yy=e[i+1].v;
				y=e[i+1].id;
				ans=d;
			}
		}
		cout<<x<<" "<<y<<" ";
		long long anss=0;
		for(int i=0;i<k;++i){
			if(((xx>>i)&1)==((yy>>i)&1)){
				//cout<<(((xx>>i)&1)^1)<<endl;
				anss+=((((xx>>i)&1)^1)<<i);
			}
		}
		cout<<anss<<endl;
	}
	return 0;
}

G. Vlad and the Mountains

显然这个Vlad具有的能量就像是势能一样,那么我们应该每次都需要知道Vlad能够走哪里。
实现很容易,但是怎样时间复杂度可以接受呢?
离散化+并查集,把道路的高度和Vlad具有的能量都进行排序,然后从小到大依照Vlad能走进行加边。
并查集查询两个山是否在同一个集合里。
时间复杂度就可以接受了.

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<ctime>
#include<bitset>
using namespace std;
const int maxn=200005;
int fa[maxn];
int find(int x){
	return fa[x]==x?x:fa[x]=find(fa[x]);
}
struct edge{
	int f;
	int to;
	int h;
}ed[maxn];
int t;
int n,m,q;
struct qu{
	int f;
	int to;
	int e;
	int num;
}que[maxn];
int x,y,z;
int ans[maxn];
int h[maxn];
bool cmp(qu x,qu y){
	return x.e<y.e;
}
bool cmp1(edge x,edge y){
	return x.h<y.h;
}
void add(int x){
	if(find(ed[x].f)!=find(ed[x].to)){
		fa[fa[ed[x].f]]=fa[ed[x].to];
	}
}
bool check(int x,int y){
	return find(x)==find(y);
}
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;++i){
			scanf("%d",&h[i]);
			fa[i]=i;
		}
		for(int i=1;i<=m;++i){
			scanf("%d%d",&ed[i].f,&ed[i].to);
			ed[i].h=max(h[ed[i].f],h[ed[i].to]);
		}
		sort(ed+1,ed+m+1,cmp1);
		scanf("%d",&q);
		for(int i=1;i<=q;++i){
			scanf("%d%d%d",&que[i].f,&que[i].to,&que[i].e);
			que[i].e+=h[que[i].f];
			que[i].num=i;
		}
		sort(que+1,que+q+1,cmp);
		int cnt=1;
		for(int i=1;i<=q;++i){
			while(cnt<=m&&ed[cnt].h<=que[i].e){
				add(cnt);
				cnt++;
			}
			ans[que[i].num]=check(que[i].f,que[i].to);
		}
		for(int i=1;i<=q;++i){
			if(ans[i]) printf("Yes\n");
			else printf("No\n");
		}
		cout<<endl;
	}
	return 0;
}