【解题报告】CF DIV2 #ROUND 723 A~D

【解题报告】CF DIV2 #ROUND 723 A~D

比赛链接

比赛评价:
发现这场十点就开了,然后就和ph巨佬一起玩了一场。我两分别再A和B罚时罚飞了,索性后面把C1,C2整出来了
排名2500+,而且极其刺激,最后3分钟找出C1错误,最后30S交了C1,C2。爽到飞起
在这里插入图片描述

A. Mean Inequality

题意
2*n个数成环,找到一个排列使得任意位置满足 2 ∗ b i ! = b i − 1 + b i + 1 2*b_i!=b_{i-1}+b_{i+1} 2bi!=bi1+bi+1
思路
先排序,然后
结果我憨憨的写sort只写了前n个,WA掉一发呜呜呜
代码

// Problem: A. Mean Inequality
// Contest: Codeforces - Codeforces Round #723 (Div. 2)
// URL: https://codeforces.com/contest/1526/problem/A
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// FishingRod

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
#define MULINPUT
/*DATA & KEY

*/
int T;
const int N=55;
LL a[N],b[N];
void solve(int C)
{
	//NEW DATA CLEAN
	
	//NOTE!!!
	int n;cin>>n;
	for(int i=1;i<=2*n;i++)cin>>a[i];
	sort(a+1,a+1+2*n);
	for(int i=1,j=1;i<=n;i++,j+=2)b[j]=a[i];
	for(int i=2*n,j=2;i>=n+1;i--,j+=2)b[j]=a[i];
	for(int i=1;i<=2*n;i++)cout<<b[i]<<" ";
	puts("");
}

int main()
{
	#ifdef MULINPUT
		scanf("%d",&T);
		for(int i=1;i<=T;i++)solve(i);
	#else
		solve(1);
	#endif
	return 0;
}

B. I Hate 1111

题意
问一个数能不能由11,111,1111……构造出来
思路
可以发现1111,11111……都可以由11,111构造出来,所以只需要考虑能否被11和111构造出来。
也就是 C = x ∗ 11 + y ∗ 111 C=x*11+y*111 C=x11+y111,要有非负整数解
有定理:可以看一下这题 小凯的疑惑
如 果 a , b 均 是 正 整 数 且 互 质 , 那 么 由 a x + b y , x ≥ 0 , y ≥ 0 不 能 凑 出 的 最 大 数 是 a b − a − b 如果 a,b均是正整数且互质,那么由 ax+by,x≥0,y≥0不能凑出的最大数是 ab−a−b a,b,ax+by,x0,y0abab
也就是最大不能凑出1,099。
然后直接枚举一波<1099能凑出的数即可

代码

#include<bits/stdc++.h>
using namespace std;
map<int,bool>mp;
int main(){
	int n;cin>>n;
	for(int i=0;i<=100;i++)
		for(int j=0;j<=10;j++)
			mp[i*11+j*111]=1;
	for(int i=1;i<=n;i++){
		int x;cin>>x;
		if(x>1099||mp[x])puts("YES");
		else puts("NO");
	}	
	return 0;
}

大佬的奇妙数论操作

// Problem: B. I Hate 1111
// Contest: Codeforces - Codeforces Round #723 (Div. 2)
// URL: https://codeforces.com/contest/1526/problem/B
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// FishingRod

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
#define MULINPUT
/*DATA & KEY

*/
int T;
void solve(int C)
{
	//NEW DATA CLEAN
	
	//NOTE!!!
	LL x;cin>>x;
	if(x%11<=x/11/10)puts("YES");
	else puts("NO");
}

int main()
{
	#ifdef MULINPUT
		scanf("%d",&T);
		for(int i=1;i<=T;i++)solve(i);
	#else
		solve(1);
	#endif
	return 0;
}

C1+C2 Potions

题意
有n瓶药水,对应值a[i],a[i]可正可负,范围正负1e9,对于每瓶药水你可以选择喝或者不喝,但是必须保证选择药水的和非负,问最多喝多少瓶。
思路
C1和C2只是n数据量不同,我直接写通解了。
主要是反悔贪心和单调队列的思想,个人是用优先队列实现的。
反悔贪心看一看这一篇文章
首先有一个显然的贪心思想就是,只要sum不会0,那就喝下药水但是这样其实是不ok的。

10 -10 -1 -2 -3

显然我们可以选择不喝-10,喝后面3瓶。那么,如何实现这一操作呢。
答案是反悔贪心。
反悔贪心主要的思想是替换和做差。
首先我们一直喝,直到继续喝下去sum可能<0。
然后我们就要思考当前x能否替换掉先前喝过的值最小的药水。
替换的条件有以下2个
①替换后sum>=0
②x比替换的值大
也就是if(sum-heap.top()+x>=0&&heap.top()<x)
代码

// Problem: C1. Potions (Easy Version)
// Contest: Codeforces - Codeforces Round #723 (Div. 2)
// URL: https://codeforces.com/contest/1526/problem/C1
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// FishingRod

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
//#define MULINPUT
/*DATA & KEY

*/
int T;
void solve(int C)
{
	//NEW DATA CLEAN
	priority_queue<LL,vector<LL>,greater<LL>>heap;
	//NOTE!!!
	int n;scanf("%d",&n);
	LL sum=0;
	for(int i=1;i<=n;i++)
	{
		LL x;scanf("%lld",&x);
		if(heap.empty())//如果空
		{
			if(x>=0)//正的直接加入
			{
				heap.push(x);
				sum+=x;
			}
		}
		else
		{
			if(x>=0)//正的直接加入
			{
				heap.push(x);
				sum+=x;
			}
			else//x<0
			{
				if(sum+x>=0)//可以喝直接加入
				{
					sum+=x;
					heap.push(x);
				}
				else
				{
					if(sum-heap.top()+x>=0&&heap.top()<x)//满足替换条件,我们就把堆顶的药水换掉
					{
						sum=sum-heap.top()+x;
						heap.pop();
						heap.push(x);
					}
					
				}

			}
		}
	}
	cout<<heap.size()<<endl;
}

int main()
{
	#ifdef MULINPUT
		scanf("%d",&T);
		for(int i=1;i<=T;i++)solve(i);
	#else
		solve(1);
	#endif
	return 0;
}

D.Kill Anton

在这里插入图片描述

题意
给你一个字符串,你要对它的字母重新排列。排列后的字符串只能通过相邻位置两两交换的方式回到原串。请你构造一个排列方式,使得它变回原串的操作次数最多。
思路
相邻交换的话,联想到冒泡排序和逆序对数量,每交换一次逆序对增加一次,也就是说让映射过去的逆序对数最多
emmm然后蒟蒻鱼竿就卡在这里了。
问了大佬,大佬说有个奇妙的结论:相同字母一定是连续的
然后直接枚举 4 ! 4! 4!种排列可能,求逆序对,记录最大的字符串即可。
在这里插入图片描述

代码

// Problem: D. Kill Anton
// Contest: Codeforces - Codeforces Round #723 (Div. 2)
// URL: https://codeforces.com/contest/1526/problem/D
// Memory Limit: 512 MB
// Time Limit: 2000 ms
// FishingRod

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
#define MULINPUT
/*DATA & KEY

*/
int T;
const int N=2E5+10;
int num[N],sort_tmp[N];
int get_id(char c)//获取对应id
{
	if(c=='A')return 0;
	if(c=='N')return 1;
	if(c=='T')return 2;
	if(c=='O')return 3;
}
LL merge_sort(int l,int r)//归并求逆序对
{
    if(l>=r)return 0;
    int mid=l+r>>1;
    LL res=merge_sort(l,mid)+merge_sort(mid+1,r);
    int k=0,i=l,j=mid+1;//i是l别打成1
    while(i<=mid&&j<=r)
    {
        if(num[i]<=num[j])sort_tmp[k++]=num[i++];
        else
        {
            sort_tmp[k++]=num[j++];
            res+=mid-i+1;//q[i]>q[j],左区间剩下的所有数与右区间当前数成为逆序对
        }
    }
    while(i<=mid)sort_tmp[k++]=num[i++];     //扫尾
    while(j<=r)sort_tmp[k++]=num[j++];
    for(int i=l,j=0;i<=r;i++,j++)num[i]=sort_tmp[j];//不要写成i=1
    return res;
}
LL get_rev(string s,int* p){//求字符串逆序对数量
	int len=s.length();
	for(int i=0;i<len;i++)
		for(int j=0;j<4;j++)
			if(get_id(s[i])==p[j])//根据排序比较规则p[j],把string映射成数组求逆序对
			{	
				num[i]=j;//下标j就是rank
				break;
			}
	return merge_sort(0,len-1);
}
void solve(int C)
{
	//NEW DATA CLEAN
	//NOTE!!!
	int p[]={0,1,2,3};//排列顺序,同时也是求逆序对数的排序比较规则
	string s;cin>>s;
	string ans,A,N,T,O;
	for(int i=0;s[i];i++)
	{
		if(s[i]=='A')A+='A';
		if(s[i]=='N')N+='N';
		if(s[i]=='T')T+='T';
		if(s[i]=='O')O+='O';
	}
	LL rev=0;
	do{
		string tmp;
		for(int i=0;i<4;i++){
			if(p[i]==0)tmp+=A;
			if(p[i]==1)tmp+=N;
			if(p[i]==2)tmp+=T;
			if(p[i]==3)tmp+=O;	
		}
		LL k=get_rev(s,p);
		if(k>=rev)
		{
			rev=k;
			ans=tmp;
		}
	}while(next_permutation(p,p+4));
	cout<<ans<<endl;
}

int main()
{
	#ifdef MULINPUT
		scanf("%d",&T);
		for(int i=1;i<=T;i++)solve(i);
	#else
		solve(1);
	#endif
	return 0;
}

反思

A:

对于成环的,使用sort或者其他东西的时候一定要注意2n而不是n

B:

问能否用给出的数构造询问的数思考以下两个
塞 尔 维 斯 特 定 理 : 如 果 a , b 均 是 正 整 数 且 互 质 , 那 么 由 a x + b y , x ≥ 0 , y ≥ 0 不 能 凑 出 的 最 大 数 是 a b − a − b 塞尔维斯特定理:如果 a,b均是正整数且互质,那么由 ax+by,x≥0,y≥0不能凑出的最大数是 ab−a−b a,b,ax+by,x0,y0abab
可以用来缩小枚举范围
给出的数之间能否相互包含相互构造

C:

反悔贪心流程
①普通贪心直到边界条件,并记录堆的相关数据
②看当前要加入数x替换堆顶元素后是否优于原来的,并且满足边界条件,并记录相关数据

如何实现替换
利用做差等操作维护堆的数据信息,堆顶的弹出,新数据插入堆

D:

相邻交换,联想到冒泡排序和逆序对

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值