Codeforces Round 895 Div. 3 前六题补题报告

得分情况

A题AC
B题AC
C题全部WA
D题过了前三组,剩下的TLE
E题没做
F题没做

补题情况

全部AC

错题分析

C题

题目大意

本题是多组输入
给出 l,r构造一组
a,b 使满足以下条件:
l ≤ a + b ≤ r l≤a+b≤r la+br
g c d ( a , b ) ≠ 1 gcd(a,b)≠1 gcd(a,b)=1
若有多组解,则输出任意一组。
若无解,则输出-1。

初次思路

暴力枚举l-r区间所有可能的数,再枚举每个数所有分解方式,如果有符合条件的就输出,否则输出-1。(但不知道怎么一分没得)

正解思路

当一个区间的长度大于等于2且l<3时,必定会出现一组解:
设x为区间内的一个偶数,(x-2,2)就是一组解。
或区间长度小于2也就是区间长度为1且r(l)为合数时,也必定会出现一组解:
设x为r(l)的一个除1和本身外的因数,(r-x,x)(或(l-x,x))就是一组解。
否则输出-1。

正解代码

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int gcd(int a,int b){
	if(a%b==0){
		return b;
	}
	return gcd(b,a%b);
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		int flag=0;
		int l,r;
		scanf("%d %d",&l,&r);
		if(l<3){
			l=3;
		}
		if(r-l+1>=2){
			if(r%2==1){
				printf("%d %d\n",2,r-1-2);
			}
			else{
				printf("%d %d\n",2,r-2);
			}
		}
		else{
			int flag=1;
			for(int i=2;i*i<=l;i++){
	            if(l%i == 0){
	                printf("%d %d\n",i,l-i);
	                flag=0;
	                break;
	            }
	        }
			if(flag){
				printf("-1\n");
			}
		}
	}
	return 0;
}

错误原因

做题时没有对利用数学构造进行考虑。

D题

题目大意

本题是多组输入
给定三个整数 n , x , y ( 1 ≤ n ≤ 1 0 9 , 1 ≤ x , y ≤ n ) n,x,y(1≤n≤10^9,1≤x,y≤n) n,x,y(1n109,1x,yn),将1到n进行排列。
设sum_x为编号为x的倍数的数求和。
设sum_y为编号为y的倍数的数求和。
求最大的sum_x-sum_y。

初次思路

如果x=y输出0,因为只能是0。
因为要使差最大,所以先求出x,y各选几个数(注:因为x,y的公倍数的位置上的数都要加进去所以放哪个数都无所谓,因此要去掉两数n以内的所有公因数),然后将大的数都往sum_x里加,将小的数都往sum_y里加,使结果最优。

正解思路

如果x=y输出0,因为只能是0。
因为要使差最大,所以先求出x,y各选几个数(注:因为x,y的公倍数的位置上的数都要加进去所以放哪个数都无所谓,因此要去掉两数n以内的所有公因数),然后利用等差数列求和公式求出sum_x和sum_y(否则会TLE)

正解代码

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
long long gcd(long long a,long long b){
	if(a==0 || b==0){
		return 0;
	} 
	if(a%b==0){
		return b;
	}
	return gcd(b,a%b);
}
long long lcm(long long a,long long b){
	if(a==0 || b==0){
		return 0;
	} 
	return a/gcd(a,b)*b;
} 
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		long long n,x,y;
		scanf("%lld %lld %lld",&n,&x,&y);
		if(x==y){
			printf("0\n");
			continue;
		}
		long long chong=n/lcm(x,y),sumx,sumy;
		x=(n/x)-chong;
		y=(n/y)-chong;
		sumx=(n+n-x+1)*x/2;
		sumy=(1+y)*y/2;
		printf("%lld\n",sumx-sumy);
	}
	return 0;
}

错误原因

做题时没有对利用数学公式优化进行考虑。

E题

题目大意

本题是多组输入
给定一个长度为 n 的数组和一个长度为 n 的二进制串 s,现有两个操作:
1 l r 表示将 l ≤ i ≤ r l≤i≤r lir的所有 s i s _i si取反(0 变 1,1 变 0)
2 g ( g ∈ 0 , 1 ) (g∈{0,1}) (g0,1),表示将所有 s i = g s _i=g si=g a i a_i ai求异或和并输出;
1 ≤ n ≤ 1 0 5 , 1 ≤ t ≤ 1 0 4 1≤n≤10^5,1≤t≤10^4 1n105,1t104

初次思路

(我都没来得及做)

正解思路

设sum0表示 s i = 0 s_i=0 si=0 a i a_i ai的异或和,sum1表示 s i = 1 s_i=1 si=1 a i a_i ai的异或和
因为N^N=0 N^0=N,所以我们可以像预处理前缀和一样预处理异或和,而取反的部分我们将取反的部分的异或和分别异或进sum0,sum1就可以达到取反的效果。

正解代码

#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
int num[100005],sum[100005];
int gcd(int a,int b){
	if(a%b==0){
		return b;
	}
	return gcd(b,a%b);
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		int n,x0=0,x1=0;
		scanf("%d",&n);
		for(int i=1;i<=n;i++){
			scanf("%d",&num[i]);
			sum[i]=sum[i-1]^num[i];
		}
		string s;
		cin>>s;
		for(int i=0;i<s.size();i++){
			
			if(s[i]=='0'){
				x0^=num[i+1];
			}
			else{
				x1^=num[i+1];
			}
		}
		int q;
		scanf("%d",&q);
		for(int i=1;i<=q;i++){
			int f;
			scanf("%d",&f);
			if(f==1){
				int l,r;
				scanf("%d %d",&l,&r);
				x0^=(sum[r]^sum[l-1]);
				x1^=(sum[r]^sum[l-1]);
			}
			else{
				int g;
				scanf("%d",&g);
				if(g==1){
					printf("%d ",x1);
				}
				else{
					printf("%d ",x0);
				}
			}
		}
		printf("\n");
	}
	return 0;
}

错误原因

(我都没来得及做)

F题

题目大意

动物园里有 n 个动物,第 i 个动物害怕第 a i a_i ai个动物,第 i 个动物价值 c i c_i ci元。
现在我要将这些动物全部卖掉。显然,卖掉的动物编号可以构成一个排列 p。
考虑卖掉这些动物时:
a i a_i ai在 i 还没有卖掉之前就被卖掉了,现在卖掉 i,可以获得 c i c_i ci元。
a i a_i ai在 i 还没有卖掉之前没被卖掉,现在卖掉 i,可以获得 2 ⋅ c i 2⋅c_i 2ci元。
构造并输出赚钱最多的动物卖出顺序。
.

初次思路

(我都没来得及做)

正解思路

我们可以定义一个优先队列,每次将害怕它的动物的总价格最小的动物卖掉(因为当这个动物害怕一个动物时这个动物的价格更高,这样可以使损失最小),最后将剩下的动物原价卖出。

正解代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;   
int n;
int a[100005],c[100005],st[100005];
long long sum[100005];
priority_queue<pair<long long,int>,vector<pair<long long,int> >,greater<pair<long long,int> > > q;
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		memset(sum,0,sizeof sum);
		memset(st,0,sizeof st);
		cin>>n;
		for(int i=1;i<=n;i++){
			cin>>a[i];
		}
		for(int i=1;i<=n;i++){
			cin>>c[i];
			sum[a[i]]+=c[i];
		}
		for(int i=1;i<=n;i++){
			q.push(make_pair(sum[i],i));
		}
		while(!q.empty()){
			int t=q.top().second;
			q.pop();
			if(st[t]){
				continue;
			}
			st[t]=1;
			cout<<t<<" ";
			sum[a[t]]-=c[t];
			q.push(make_pair(sum[a[t]],a[t]));
		}
		cout<<"\n";
	}
	return 0;
}

错误原因

(我都没来得及做)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值