cf #696 div2

C. Array Destruction

题意:

给一个长度为2n的数列,每次可选择和为x的两个数删掉,然后x变为删掉的两个数中较大的数。初始的x可自由设置。
问是否能把数列删完

题解:

首先要删完数列,最大的数肯定是最先删掉。
看到n比较小,可以暴力枚举和最大的数一起删掉的数。
然后模拟就好了。

#include<bits/stdc++.h>
using namespace std;

const int maxn=1e6+5;
int cnt[maxn],a[2005];

int main()
{
	int t,n,m;
	int flag,fl;
	int last,x;
	scanf("%d",&t);
	while(t--){
		flag=0;
		scanf("%d",&m);
		n=(m<<1);
		for(int i=1;i<=n;i++)scanf("%d",&a[i]),cnt[a[i]]++;
		sort(a+1,a+1+n);
		for(int j=1;j<n;j++){
			x=a[j]+a[n];
			last=a[n];
			cnt[a[j]]--; cnt[a[n]]--;
			for(int i=n-1;i>0;i--){
				if(cnt[a[i]]==0)continue;
				else{
					cnt[a[i]]--;
					if(cnt[last-a[i]]>0){
						cnt[last-a[i]]--;
						last=a[i];
					}
					else{
						cnt[a[i]]++;
						break;
					}
				}
			}
			fl=1;
			for(int i=1;i<=n;i++){
				if(cnt[a[i]]>0){
					fl=0; break;
				}
			}
			for(int i=1;i<=n;i++)cnt[a[i]]=0;
			for(int i=1;i<=n;i++)cnt[a[i]]++;
			if(fl){
				flag=1; break;
			}
		}
		if(flag){
			printf("YES\n%d\n",x);
			printf("%d %d\n",a[n],x-a[n]);
			cnt[a[n]]--; cnt[x-a[n]]--;
			last=a[n];
			for(int i=n-1;i>0;i--){
				if(cnt[a[i]]){
					printf("%d %d\n",a[i],last-a[i]);
					cnt[a[i]]--; cnt[last-a[i]]--;
					last=a[i];
				}
			}
		}
		else printf("NO\n");
		for(int i=1;i<=n;i++)cnt[a[i]]=0;
	}
	return 0;
}

E. What Is It?

题意:

有如下操作:选i,j使得a[j]=i,然后交换a[j]和a[i],得到(i-j)2 的分数。
给你一个n,构造长度为n的排列,使得操作完分数最大,并给出最大分数和操作步骤。

题解:

手玩发现,如下图能得到最大分数,奇偶分情况。
然后操作的话,那长度为6的举例,操作为:
(1,4)(1,5)(6,3)(6,2)(1,6)。
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;

int a[100005];
long long sum;

int main()
{
	int t,n;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		if(n&1){
			sum=0;
			for(int i=n/2;i<n;i++)sum+=1ll*i*i*2;
			sum-=1ll*(n/2)*(n/2);
			sum-=1ll*(n-1)*(n-1);
			printf("%lld\n",sum);
			for(int i=(n+1)/2;i<n;i++)a[i]=i+1;
			a[1]=(n+1)/2;
			a[n]=n/2;
			for(int i=n/2;i>1;i--)a[i]=i-1;
			for(int i=1;i<=n;i++)printf("%d ",a[i]);
			printf("\n%d\n",n-1);
			for(int i=(n+1)/2;i<n;i++)printf("%d 1\n",i);
			for(int i=n/2;i>1;i--)printf("%d %d\n",i,n);
			printf("%d 1\n",n);
		}
		else{
			sum=0;
			for(int i=n/2;i<n;i++){
				sum+=1ll*i*i*2;
			}
			sum-=1ll*(n-1)*(n-1);
			printf("%lld\n",sum);
			for(int i=n/2+1;i<n;i++)a[i]=i+1;
			a[1]=n/2+1;
			a[n]=n/2;
			for(int i=n/2;i>1;i--)a[i]=i-1;
			for(int i=1;i<=n;i++)printf("%d ",a[i]);
			printf("\n%d\n",n-1);
			for(int i=n/2+1;i<n;i++)printf("%d 1\n",i);
			for(int i=n/2;i>1;i--)printf("%d %d\n",i,n);
			printf("%d 1\n",n);
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值