比赛链接
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<<'
';
}
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<<'
';
}
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<<'
';
}
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<<'
';
return 0;
}