Codeforces Round #645 (Div. 2) A~D

比赛链接
https://codeforces.com/contest/1358

A. Park Lighting

题意

在一个矩形中放入路灯,在两个方块公共边上放上路灯则两个方块都可以被照亮,问将矩形块全部照亮需要的最少路灯。

思路

先将n视为偶数,则全部照亮需要(n/2)m个路灯,如果n为奇数,则最后还剩下1m的矩形块,然后加上(m+1)/2个路灯即可

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 5e5+5;
ll t,n,m,x,a[N],sum[N],sum2[N];
int d[2][2]={1,0,0,1};

int main(){
	cin>>t;
	while(t--){
		cin>>n>>m;
		ll ans=(n/2)*m;
		if(n&1) ans+=(m+1)/2;
		cout<<ans<<'\n';
	} 
	
	return 0;
} 

B. Maria Breaks the Self-isolation

题意

maria想邀请尽可能多的老奶奶聚会,但第i个老奶奶到时都必须有不少于 \(a_i\) 个老奶奶在场(除自己外)。

思路

先将数组从小到大排序,因为要求尽可能多的人聚,所以从后向前遍历,当遍历到i时,如果i+1>a[i],即满足条件。i表示同时到场人数。

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5+5;
int t,n,m,a[N];

int main(){
	cin>>t;
	while(t--){
		cin>>n;
		for(int i=1;i<=n;i++) cin>>a[i];
		sort(a+1,a+n+1);
		int ans=1;
		for(int i=n;i>=1;i--){
			if(ans+i>a[i]){
				ans=ans+i;
				break;
			}
		}
		cout<<ans<<'\n';
	}
	
	return 0;
} 

C. Celex Update

题意

给定两点坐标,问从一点到另外一点所需权值的不同值有多少。权值即路径上方块值的和。

思路

点只能向右向下移动,观察可以发现,权值最小值路径为(x1,y1)->(x2,y1)->(x2,y2);权值最大值为(x1,y1)->(x1,y2)->(x2,y2);
现在将最小值向最大值靠拢,可以发现一个田字格的右上角和左下角的数相差1,可以这样先向坐移动再向下移动。这样就会得到最大值。
这个过程需要(x2-x1)*(y2-y1)+1步。(解释不清,可以去看官方题解:https://codeforces.com/blog/entry/77869)

#include<bits/stdc++.h>
 
using namespace std;
typedef long long ll;
const int N = 1e5+5;
ll t,n,m,a[N],x1,x2,y1,y2;
int d[2][2]={1,0,0,1};
 
 
int main(){
	cin>>t;
	while(t--){
		cin>>x1>>y1>>x2>>y2;
		cout<<(x2-x1)*(y2-y1)+1<<'\n';
	}
	
	return 0;
} 

D. The Best Vacation

题意

一个数组,a[i]表示第i月有a[i]天。在某个月的第j天去会得到j个拥抱,问连续x天最多可以得到的拥抱

思路

连续的x天可能不在同一年,所以可以将数组存储两遍。
sum1[i]表示a[1]a[i]的总天数,sum[2]表示a[1]a[i]的总拥抱数
1~2*n间寻找区间左端点,然后找满足条件的最大值。

前缀和+二分找左端点。

#include<bits/stdc++.h>
 
using namespace std;
typedef long long ll;
const int N = 4e5+5;
ll t,n,m,x,a[N],sum1[N],sum2[N];
int d[2][2]={1,0,0,1};
 
ll cal(ll a){
	return a*(1+a)/2;
}
 
int main(){
	cin>>n>>x;
	for(int i=1;i<=n;i++) cin>>a[i],a[i+n]=a[i];
	for(int i=1;i<=n*2;i++)
	{
	  	sum1[i]=sum1[i-1]+a[i];
		sum2[i]=sum2[i-1]+cal(a[i]);
	} 	
	ll ans=0;
	for(int i=1;i<=n*2;i++)
	{
		if(sum1[i]<=x){//如果总天数小于等于x,则ans可取当前的总拥抱数。
			ans=max(ans,sum2[i]);
			continue;
		}
		ll l=0,r=i;
		while(l<r)//找区间左端点
		{
			ll mid = l+r+1>>1;
			if(sum1[i]-sum1[mid]<x) r=mid-1;
			else l=mid;
		}
		if(x>sum1[i]-sum1[l+1])
		{
			ll res=sum2[i]-sum2[l+1];//l+1月的天数可能没有用完
			ll tmp=x-sum1[i]+sum1[l+1];
			res+=(cal(a[l+1])-cal(a[l+1]-tmp));
			ans=max(ans,res);
		}
	}
	cout<<ans<<'\n';
	
	return 0;
} 
posted @ 2020-05-27 15:05  voids5  阅读(120)  评论(2编辑  收藏  举报