Codeforces Round#521(Div.3)题解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/C_13579/article/details/84305218

虚拟赛做了6个,也还可以了,由于第四题卡了一下(除数为0)有点炸,最后一题分析一下状态转移方程还是比较容易看出来用优先队列来优化

地址:http://codeforces.com/contest/1077

A. Frog Jumping

思路:签到题,只要long long即可

Code:

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

const int MAX_N=1e5+5;
LL n,m,T;

int main()
{
	ios::sync_with_stdio(false);
	cin>>T;
	LL a,b;
	while(T--){
		cin>>a>>b>>n;
		LL t=a-b;
		LL ans=t*(n/2);
		if(n%2==1)	ans+=a;
		cout<<ans<<endl;
	}
	
	return 0;
}

B. Disturbed People

思路:遍历一遍,若a[i]满足要求则更改掉a[i+1]=0即可

Code:

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

const int MAX_N=1e2+5;
int n,m,T;
int a[MAX_N];

int main()
{
	ios::sync_with_stdio(false);
	cin>>n;
	for(int i=1;i<=n;++i)
		cin>>a[i];
	int ans=0;
	for(int i=2;i<n;++i)
		if(!a[i]&&a[i-1]&&a[i+1]){
			++ans;	a[i+1]=0;
		}
	cout<<ans<<endl;
	
	return 0;
}

C. Good Array

思路:先求出所有a[i]的和Sum以及用记录a[i]的个数b[a[i]]。再遍历a[i],若t=(Sum-a[i])/2存在以及不是 t==a[i]&&b[i]==1的情况,则答案加上i.

Code:

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

const int MAX_N=1e6+5;
int n,m,T;
int a[MAX_N],b[MAX_N],d[MAX_N];

int main()
{
	scanf("%d",&n);
	LL Sum=0;
	for(int i=1;i<=n;++i)
	{
		scanf("%d",&a[i]);
		Sum+=a[i];
		++b[a[i]];
	}
	int ans=0;
	LL t;
	for(int i=1;i<=n;++i)
	{
		t=(Sum-a[i])/2;
		if(t+t==Sum-a[i]&&t<MAX_N&&b[t]){
			if(t==a[i]&&b[t]==1)	continue;
			d[ans++]=i;
		}
	}
	printf("%d\n",ans);
	for(int i=0;i<ans-1;++i)
		printf("%d ",d[i]); 
	if(ans)	printf("%d\n",d[ans-1]);
	
	return 0;
}

D. Cutting Out

思路:二分查找

先将x的个数按由大到小排序,再二分查找每个元素的最大个数,再按照最大个数求出答案即可

Code:

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

const int MAX_N=2e5+5;
struct node{
	int x;
	int s;
	bool operator<(const node &p)const{
		return s>p.s;
	}
};
int n,m,ni,T;
int res[MAX_N];
node d[MAX_N];
map<int,int> imap;

bool judge(int h);
int main()
{
	ios::sync_with_stdio(false);
	cin>>n>>m;
	for(int i=0,x;i<n;++i)
	{
		cin>>x;
		++imap[x];
	}
	ni=0;
	for(auto c:imap)
		d[ni++]=node{c.first,c.second};
	sort(d,d+ni);
	int l=0,r=d[0].s,h;
	while(l<=r){
		h=(l+r)/2;
		if(judge(h))	l=h+1;
		else	r=h-1;
	}
	int t=0,s;
	for(int i=0;i<ni;++i)
	{
		s=d[i].s/r;
		for(int j=0;j<s;++j)
			res[t++]=d[i].x;
		if(t>=m)	break;
	}
	for(int i=0;i<m-1;++i)
		cout<<res[i]<<" ";
	cout<<res[m-1]<<endl;
	
	return 0;
}

bool judge(int h)
{
	if(h==0)	return true;//直接返回true,d[i].s/h不能为0
	bool boo=true;
	int t=0;
	for(int i=0;i<ni;++i)
	{
		if(t>m||d[i].s<h)	break;
		t+=d[i].s/h;
	}
	if(t<m)	boo=false;
	return boo;
}

E. Thematic Contests

思路:枚举+二分查找

先将相同ai的个数按照由小到大排序(利用map)存到d[ni]中,在对于第一场比赛的题目数t进行枚举,再用二分查找2*t,最后取最大值即可

Code:

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

const int MAX_N=2e5+5;
struct node{
	int x;
	int s;
	bool operator<(const node &p)const{
		return s<p.s;
	}
};
int n,m,ni,T;
node d[MAX_N];
map<int,int> imap;

bool judge(int h);
int main()
{
	ios::sync_with_stdio(false);
	cin>>n;
	for(int i=0,x;i<n;++i)
	{
		cin>>x;
		++imap[x];
	}
	ni=0;
	for(auto c:imap)
		d[ni++]=node{c.first,c.second};
	sort(d,d+ni);
	int ans=0,Sum,t,si,l;
	for(int k=1;k<=n;++k)
	{
		Sum=0;	t=k;	l=0;
		si=lower_bound(d+l,d+ni,node{0,t})-d;
		while(si<ni){
			Sum+=t;	t*=2;
			l=si+1;
			si=lower_bound(d+l,d+ni,node{0,t})-d;
		}
		ans=max(ans,Sum);
	}
	cout<<ans<<endl;
	
	return 0;
}

F1. Pictures with Kittens (easy version)

思路:dp

dp[i][j]:表示第j次时取第i个图片时的最大价值

那么 dp[i][j]=max{dp[k][j-1]}  (i-m<=k<=i-1) ,其中m为最大间距

时间复杂度为O(n*m*s) s取的图片数量,由于n,m,s<=200,因此不会超时

Code:

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

const int MAX_N=2e2+5;
int n,m,s;
int a[MAX_N];
LL dp[MAX_N][MAX_N];
LL pre[MAX_N][MAX_N];

int main()
{
	scanf("%d%d%d",&n,&m,&s);
	for(int i=1;i<=n;++i)
		scanf("%d",&a[i]);
	for(int i=1;i<=m;++i)
		dp[i][1]=a[i];
	for(int i=2;i<=n;++i)
		for(int j=1;j<=s;++j)
		{
			for(int k=i-m;k<i;++k)
				if(k>0&&dp[k][j-1])	dp[i][j]=max(dp[i][j],dp[k][j-1]);
			if(i<=m&&j==1)	continue;
			if(dp[i][j])	dp[i][j]+=a[i];
		}
	LL ans=0;
	for(int i=n-m+1;i<=n;++i)
		ans=max(ans,dp[i][s]);
	if(!ans)	ans=-1;
	printf("%lld\n",ans);
	
	return 0;
}

F2. Pictures with Kittens (hard version)

思路:dp+优先队列

这题较上一题的数据范围变为了5000,因此O(n*m*s)会超时,对于状态转移方程

dp[i][j]=max{dp[k][j-1]}  (i-m<=k<=i-1) ,其中m为最大间距

分析一下发现,其中max(dp[k][j-1]}是可以用优先队列优化的,用优先队列Q维护{dp[i][j-1],i}(以dp[i][j-1]按大的优先),当求dp[i][j]时,将Q.top()的元素下标大于i-m的出队列,再取Q.top()即可

Code:

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

const int MAX_N=5e3+5;
int n,m,s;
int a[MAX_N];
LL dp[MAX_N][MAX_N];
priority_queue<pr> Q;

int main()
{
	scanf("%d%d%d",&n,&m,&s);
	for(int i=1;i<=n;++i)
		scanf("%d",&a[i]);
	for(int i=1;i<=m;++i)
		dp[i][1]=a[i];
	for(int j=2;j<=s;++j)
	{
		while(!Q.empty()){
			Q.pop();
		}
		for(int i=1;i<=n;++i)
		{
			while(!Q.empty()&&Q.top().second<i-m){
				Q.pop();
			}
			if(!Q.empty()){
				dp[i][j]=Q.top().first+a[i];
			}
			if(dp[i][j-1])	Q.push(pr{dp[i][j-1],i});
		}
	}
	
	LL ans=0;
	for(int i=n-m+1;i<=n;++i)
		ans=max(ans,dp[i][s]);
	if(!ans)	ans=-1;
	printf("%lld\n",ans);
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/C_13579/article/details/84305218