Codeforces Round #560 (Div. 3)-题解

44 篇文章 0 订阅
42 篇文章 0 订阅

地址:https://codeforces.com/contest/1165

A. Remainder

思路:后x位中,其中只有后第y+1位为1,其余全是0才是合法,因此根据这个来判断后x位不合法的个数即可

Code:

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;

int n,x,y;
string str;

int main()
{
	ios::sync_with_stdio(false);
	cin>>n>>x>>y>>str;
	char ch;
	int res=0;
	for(int i=1;i<=x;++i)
	{
		ch=str[n-i];
		if(i!=y+1){
			if(ch=='1')	++res;
		}else	if(i==y+1){
			if(ch=='0')	++res;
		}
	}
	cout<<res<<endl;
	
	return 0;
}

 

B. Polycarp Training

思路:求 l从1开始 a[i]>=l的最大l ,贪心,由小到大排序,然后每次用最小的a[i]来满足条件即可

Code:

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;

const int MAX_N=2e5+5;
int n,x,y;
int a[MAX_N];

int main()
{
	ios::sync_with_stdio(false);
	cin>>n;
	for(int i=0;i<n;++i)
		cin>>a[i];
	sort(a,a+n);
	int res=0;
	for(int i=0;i<n;++i)
		if(a[i]>res)	++res;
	cout<<res<<endl;
	
	return 0;
}

 

C. Good String

思路:直接贪心,遍历str,同时记录ch=str[i-1]的位置奇偶性p,与str[i]比较,若当前为奇数p=1,且ch==str[i]则去掉str[i]即可,

最后若剩下的个数为奇数个,则在去掉末尾的一个即可

Code:

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;

const int MAX_N=2e5+5;
int n;
string str;
bool boo[MAX_N];

int main()
{
	ios::sync_with_stdio(false);
	cin>>n>>str;
	int res=0,p=1;
	char ch=str[0];
	for(int i=1;i<n;++i)
		if(p&&ch==str[i]){
			boo[i]=true;
			++res;
		}else{
			ch=str[i];
			p=(p+1)%2;
		}
	if((n-res)%2){
		++res;
		for(int i=n-1;i>=0;--i)
			if(!boo[i]){
				boo[i]=true;	break;
			}
	}
	cout<<res<<endl;
	for(int i=0;i<n;++i)
		if(!boo[i])	cout<<str[i];
	cout<<endl;
	
	return 0;
}

 

D. Almost All Divisors

思路:将a[i]由小到大排序,因子都是左右两两成对的,则ans=a[0]*a[n-1],在遍历ans的因子 i [2,sqrt(ans)],判断 ans的所有因子是否在a[i]中,若不在则 ans=-1,最后在判断 a[i]中是否有多余的数 a[i]*a[n-i-1]!=ans 若有则 ans=-1.

Code:

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;

const int MAX_N=3e2+5;
int n,T;
LL a[MAX_N];

int main()
{
	ios::sync_with_stdio(false);
	cin>>T;
	while(T--){
		cin>>n;
		for(int i=0;i<n;++i)
			cin>>a[i];
		sort(a,a+n);
		LL ans=a[0]*a[n-1];
		LL qn=sqrt(ans);
		int l=0;
		for(int i=2;i<=qn;++i)
			if(ans%i==0){
				if(a[l]!=i||a[l]*a[n-l-1]!=ans){
					ans=-1;	break;
				}
				++l;
			}
		qn=(n+1)/2;
		for(int i=l;i<qn;++i)
			if(a[i]*a[n-i-1]!=ans){
				ans=-1;	break;
			}
		cout<<ans<<endl;
	}
	
	return 0;
}

 

E. Two Arrays and Sum of Functions

思路:取n=4,计算ans可以发现,每个a[i] (i=[0,n-1])会计算 (i+1)*(n-i)遍,那么可以将 a[i]*=(i+1)*(n-i),这样ans就转化为求 sum{a[i]*b[i]}的最小值了。

而b[i]可以任意排序,那么最小值就为a[i]的第k小值*b[i]的第k大值。因此将 a[i],b[i]分别由小到大排序,ans=sum{a[i]*b[n-i-1]}%MOD即可

Code:

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;

const int MAX_N=2e5+5;
const LL MOD=(LL)998244353;
int n;
LL a[MAX_N],b[MAX_N];

int main()
{
	ios::sync_with_stdio(false);
	cin>>n;
	for(int i=0;i<n;++i)
		cin>>a[i];
	for(int i=0;i<n;++i)
		cin>>b[i];
	for(int i=0;i<n;++i)
		a[i]=a[i]*(i+1)*(LL)(n-i);
	sort(a,a+n);
	sort(b,b+n);
	LL ans=0;
	for(int i=0;i<n;++i)
		ans=(ans+a[i]%MOD*b[n-i-1]%MOD)%MOD;
	cout<<ans<<endl;
	
	return 0;
}

 

F2. Microtransactions (hard version)

思路:二分查找+贪心

二分答案h, 而对于 ki ,用pair d{di,ki}保存ki能够打折且di<h的最大距离 di,对d由小到大排序,遍历d[i],利用贪心思路,将所有的钱用来买最后打折的ki,同时记录买完后剩下的钱S或不能够打折的数量Sum,

当前di<=h且没有打折商品时,计算购买天数ans的值,但di>h时,计算ans的值,以及遍历后商品全部打折(没有计算ans)时ans的值,最后与二分答案h比较来更新 (l,r)即可

Code:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
typedef pair<int,int> pr;

const int MAX_N=2e5+5;
const int INF=1e8;
int n,m;
int a[MAX_N];
pr d[MAX_N],dd[MAX_N];

bool judge(LL h);
int main()
{
	ios::sync_with_stdio(false);
	cin>>n>>m;
	for(int i=1;i<=n;d[i].second=i,++i)
		cin>>a[i];
	int di,ti;
	for(int i=0;i<m;++i)
	{
		cin>>di>>ti;
		dd[i]={di,ti};
	}
	sort(dd,dd+m);
	int l=1,r=1e7,h;
	while(l<=r){
		h=(l+r)/2;
		if(judge(h))	r=h-1;
		else	l=h+1;
	}
	cout<<l<<endl;
	
	return 0;
}

bool judge(LL h)
{
	memset(d,0,sizeof(d));
	int ti,di;
	for(int i=0;i<m;++i)
	{
		di=dd[i].first;	ti=dd[i].second;
		if(di>h)	break;
		d[ti].first=max(d[ti].first,di);
	}
	LL Sum1=0;
	for(int i=1;i<=n;++i)
	{
		d[i].second=i;
		if(!d[i].first){
			d[i].first=INF;
			Sum1+=a[i];
		}
	}
	sort(d+1,d+n+1);
	bool boo=true;
	int x;
	LL ans=-1,S=0,Sum=0,l=0;
	for(int i=1;i<=n;++i)
	{
		if(d[i].first<=h){
			if(d[i].first!=INF){
				S+=d[i].first-l;	l=d[i].first;
				x=d[i].second;
				if(S>a[x]){
					S-=a[x];
				}else{
					Sum+=a[x]-S;	S=0;
				}
			}else{
				if(S<=Sum*2+Sum1*2){
					Sum=Sum*2+Sum1*2;
					ans=l+Sum-S;
				}else{
					ans=h;
				}
				break;
			}
		}else{
			for(int j=i;j<=n;++j)
				if(d[j].first!=INF)	Sum+=a[j];
				else	break;
			Sum=Sum*2+Sum1*2;
			ans=l+Sum-S;
			break;
		}
	}
	if(ans==-1){
		ans=l+Sum*2-S;
	}
	if(ans>h)	boo=false;
	return boo;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值