【Codeforces Round #569 (Div. 2)】 题解

A

小学数学题

#include<bits/stdc++.h>

using namespace std;
long long f[102];
void init(){
	f[1]=1;
	for(int i=2;i<=101;i++){
		f[i]=f[i-1]+(i-1)*4;
	}
}
int main(){
	init();
	int n;
	cin>>n;cout<<f[n]<<endl;
	return 0;
}

B

题意:

现在有一个数组,你可以选择若干个 a i a_i ai将它们变成 − a i − 1 -a_i-1 ai1,使得他们的乘积最大。输出一种可行方案

思路:

先把所有的非负数变为 − a i − 1 -a_i-1 ai1,然后统计现在负数的个数,若为偶数,则不操作,否则选择最小的那个负数变为 − a i − 1 -a_i-1 ai1

代码:

#include<bits/stdc++.h>

using namespace std;
const int N = 1e6+100;
int a[N];
int main(){
	int n;
	int neg=0;
	cin>>n;for(int i=1;i<=n;i++){
		cin>>a[i];if(a[i]>=0) a[i]=-a[i]-1;
	} 
	for(int i=1;i<=n;i++){
		if(a[i]<0) neg++;
	}
	if(neg&1){
		int minn=0;
		for(int i=1;i<=n;i++) minn=min(minn,a[i]);
		for(int i=1;i<=n;i++){
			if(a[i]==minn){
				a[i]=-a[i]-1;break;
			}
		}
	}
	for(int i=1;i<=n;i++) cout<<a[i]<<' ';
	cout<<endl;
	return 0; 
}

C

题意:

一个长度为 n n n的双端队列,你执行无数次下列操作:取出队列顶端的前两个数 a , b a,b a,b,大的放在队列顶端,小的放到队列尾部,现在给你 q q q次查询,查询每次操作的 a , b a,b a,b

思路:

手动模拟一遍一会发现,前 n n n次是不确定的,经过 n n n次之后变成了每 n − 1 n-1 n1次一个循环,因此只需先记录 2 ∗ n − 1 2*n-1 2n1次,然后对于查询直接查询即可,复杂度 O ( n ∗ l o g ( n ) ) O(n*log(n)) O(nlog(n))

代码:

#include<bits/stdc++.h>

using namespace std;
int main(){
	long long n,m,x;
	scanf("%I64d%I64d",&n,&m); 
	map<long long ,pair<long long,long long> > mmp1,mmp2;
	deque<long long> q;
	for(int i=1;i<=n;i++){
		scanf("%I64d",&x);q.push_back(x);
	}
	for(int j=1;j<=n;j++){
		int A=q.front();q.pop_front();
		int B=q.front();q.pop_front();
		//cout<<j<<' '<<A<<' '<<B<<endl;
		mmp1[j]={A,B};
		if(A>B){
			q.push_front(A);
			q.push_back(B);
		}
		else{
			q.push_front(B);
			q.push_back(A);			
		}
	}
	for(int j=1;j<=n-1;j++){
		int A=q.front();q.pop_front();
		int B=q.front();q.pop_front();
		//cout<<j<<' '<<A<<' '<<B<<endl;
		mmp2[j]={A,B};
		if(A>B){
			q.push_front(A);
			q.push_back(B);
		}
		else{
			q.push_front(B);
			q.push_back(A);			
		}
	}
	long long Q;
	while(m--){
		scanf("%I64d",&Q);
		if(Q<=n){
			printf("%I64d %I64d\n",mmp1[Q].first,mmp1[Q].second);
		}
		else{
			Q-=n;
			if(Q%(n-1)==0) printf("%I64d %I64d\n",mmp2[n-1].first,mmp2[n-1].second);
			else printf("%I64d %I64d\n",mmp2[Q%(n-1)].first,mmp2[Q%(n-1)].second);
		}
	}
	return 0;
} 

D

题意:

一个 n ∗ m n*m nm的网状图,你要访问每个格点,你的初始格点在 ( 1 , 1 ) (1,1) (1,1),现在你可以从 ( x , y ) (x,y) (x,y)到达 ( x + d x , y + d y ) (x+dx,y+dy) (x+dx,y+dy),你要构造一个遍历顺序使得每次的 d x , d y dx,dy dx,dy都不相同并且能遍历完所有的点。

思路

( 1 , 1 ) − &gt; ( n , m ) − &gt; ( n , m − 1 ) − &gt; ( 1 , 2 ) − &gt; . . . . . . − &gt; ( n , 1 ) − &gt; ( 2 , 1 ) . . . . . (1,1)-&gt;(n,m)-&gt;(n,m-1)-&gt;(1,2)-&gt;......-&gt;(n,1)-&gt;(2,1)..... (1,1)>(n,m)>(n,m1)>(1,2)>......>(n,1)>(2,1).....

#include<bits/stdc++.h>

using namespace std;
int main(){
	int n,m;cin>>n>>m;
	for(int i=1;i<=n/2;i++){
		for(int j=1;j<=m;j++){
			printf("%d %d\n",i,j);
			printf("%d %d\n",n+1-i,m+1-j);
			//<<n+1-i<<' '<<m+1-j<<endl;
		} 
	}
	if(n&1){
		if(m&1){
			for(int i=1;i<=m/2;i++){
				printf("%d %d\n",n/2+1,i);
				printf("%d %d\n",n/2+1,m+1-i);
			}
			printf("%d %d\n",n/2+1,m/2+1);
			//cout<<n/2+1<<' '<<m/2+1<<endl; 
		}
		else{
			for(int i=1;i<=m/2;i++){
				printf("%d %d\n",n/2+1,i);
				printf("%d %d\n",n/2+1,m+1-i);
				//cout<<n/2+1<<' '<<m+1-i<<endl;
			}			
		}
	}
	return 0;
}

E

题意:

n n n盘菜, m m m个学生,每盘菜的价格为 a i a_i ai,每个学生带的钱为 b i b_i bi,每个学生会买他所能买的最贵的菜,现在有 q q q次修改,每次你可以把 a i a_i ai变为 x x x,或者把 b i b_i bi变为 x x x,对于每次修改,计算剩下的最贵的菜的价格,如果没有,则输出 − 1 -1 1

思路:

对于每个 a i a_i ai,我们将区间 [ 1 , a i ] [1,a_i] [1,ai] 1 1 1,对于每个 b i b_i bi,我们将区间 [ 1 , b i ] [1,b_i] [1,bi] 1 1 1,每次查询统计最大的不为 0 0 0的数,如果没有输出 − 1 -1 1,线段树即可完成操作,复杂度 O ( n ∗ l o g ( n ) ) O(n*log(n)) O(nlog(n))

代码:

#include<bits/stdc++.h>

using namespace std;
const int N = 2e6+100;
int tag[N<<1],maxx[N<<1];
int a[N],b[N];
void pushdown(int rt,int l,int r){
	if(tag[rt]){
		tag[rt<<1]+=tag[rt];
		tag[rt<<1|1]+=tag[rt];
		maxx[rt<<1]+=tag[rt];
		maxx[rt<<1|1]+=tag[rt];
		tag[rt]=0;
	}
}
void update(int rt,int nl,int nr,int l,int r,int x){
	if(nl<=l&&r<=nr){
		maxx[rt]+=x;
		tag[rt]+=x;
		return ;
	}
	int mid=(l+r)>>1;
	pushdown(rt,l,r);
	if(nl<=mid) update(rt<<1,nl,nr,l,mid,x);
	if(nr>mid) update(rt<<1|1,nl,nr,mid+1,r,x);
	maxx[rt]=max(maxx[rt<<1|1],maxx[rt<<1]);
}
int query(int rt,int l,int r){
	if(l==r){
		return l;
	}
	int mid=(l+r)>>1;
	pushdown(rt,l,r);
	if(maxx[rt<<1|1]>0){
		return query(rt<<1|1,mid+1,r);
	}
	return query(rt<<1,l,mid);
}
int main(){
	int n,m,q;
	scanf("%d %d",&n,&m);
	memset(maxx,0,sizeof(maxx));
	memset(tag,0,sizeof(tag));
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),update(1,1,a[i],1,2000002,1);
	for(int i=1;i<=m;i++) scanf("%d",&b[i]),update(1,1,b[i],1,2000002,-1);
	//cout<<query(1,1,2000002)<<endl;
	scanf("%d",&q);
	while(q--){
		int op,id,num;
		scanf("%d %d %d",&op,&id,&num);
		if(op==1){
			update(1,1,a[id],1,2000002,-1);
			a[id]=num;
			update(1,1,a[id],1,2000002,1);
		}
		else{
				update(1,1,b[id],1,2000002,1);
				b[id]=num;
				update(1,1,b[id],1,2000002,-1);		
		}
		int ok=query(1,1,2000002);
		if(maxx[1]<=0) puts("-1");
		else printf("%d\n",ok);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值