链接:https://codeforces.com/contest/1313
来源:codeforces
文章目录
A. Fast Food Restaurant(贪心)
思路:直接贪心的取,对三个数进行排序,贪心匹配
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int a[maxn];
int main(){
int T; scanf("%d",&T);
while(T--){
scanf("%d%d%d",&a[1],&a[2],&a[3]);
sort(a+1,a+4);
if(a[3]==0) puts("0");
else if(a[2]==0) puts("1");
else if(a[1]==0){
int cnt=2;
a[2]--; a[3]--;
if(a[2]) cnt++;
printf("%d\n",cnt);
}else{
int cnt=3;
a[1]--; a[2]--; a[3]--;
if(a[1]&&a[3]) { a[3]--;a[1]--;cnt++; }
if(a[2]&&a[3]) { a[3]--;a[2]--;cnt++; }
if(a[1]&&a[2]) { a[1]--;a[2]--;cnt++; }
if(a[1]&&a[2]&&a[3]) cnt++;
printf("%d\n",cnt);
}
}
return 0;
}
B. Different Rules(思维)
思路: m i n : min: min: ( l + r ) − n (l+r)-n (l+r)−n [ 1 , l + r − n ] [1,l+r-n] [1,l+r−n] 这个区间的数字无论和谁组合都会小于等于 l + r l+r l+r,所以这些数字无论如何组合都不会大于 [ l + r ] [l+r] [l+r] m a x : max: max:我们考虑 1 1 1 和什么数字相加的时候等于 l + r l+r l+r,那么这个区间以内的数都可以互相结合小于等于 l + r l+r l+r 此区间就是 [ 1 , l + r − 1 ] [1, l+r-1] [1,l+r−1]。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
int T; scanf("%d",&T);
while(T--){
ll n,l,r;
scanf("%lld%lld%lld",&n,&l,&r);
printf("%lld %lld\n",min(max((l+r)-n+1,1ll),n),min(l+r-1,n));
}
return 0;
}
C1. Skyscrapers (easy version)(枚举)
思路:我们枚举每一个峰值,那么他左边的数字一定都是递减的,右边的数字一定都是递增的,直接枚举判断即可。注意数据范围:long long
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e3+10;
int a[maxn],b[maxn];
int main(){
int n; scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
ll MMax=INT_MIN; int inx=-1;
for(int i=1;i<=n;i++){
int Max=a[i]; ll sum=a[i];
for(int j=i-1;j>=1;j--) { Max=min(a[j],Max); b[i]=Max; sum+=(ll)b[i]; }
Max=a[i];
for(int j=i+1;j<=n;j++) { Max=min(a[j],Max); b[i]=Max; sum+=(ll)b[i]; }
// for(int j=1;j<=n;j++) cout<<b[i]<<" ";
if(MMax<sum) { MMax=sum;inx=i; }
}
int Max=a[inx];
for(int i=inx;i>=1;i--) { Max=min(a[i],Max); a[i]=Max; }
Max=a[inx];
for(int i=inx;i<=n;i++) { Max=min(a[i],Max); a[i]=Max; }
for(int i=1;i<=n;i++) printf("%d%c",a[i],i==n?'\n':' ');
return 0;
}
C2. Skyscrapers (hard version)(单调栈)
思路:此题目相对于上面一题只是数据范围发生了变化,在找峰值的时候,对于左右两边的和我们可以进行优化,我们找到每个数字左侧的小于等于它本身的第一个数,右侧小于等于它本身的最后一个数。(这个过程可以通过单调栈来实现),接下来我们就可以计算出来每一点为峰值的时候它左右两侧的和(两边都是递减的)。然后遍历数组找到和最大的那个点。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+10;
int a[maxn];
stack<int>stk;
int l[maxn],r[maxn];
ll L[maxn],R[maxn];
int main(){
int n; scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++){
while(stk.size()&&a[stk.top()]>a[i]) stk.pop();
if(stk.empty()) l[i]=0;
else l[i]=stk.top();
stk.push(i);
}
while(stk.size()) stk.pop();
for(int i=n;i>=1;i--){
while(stk.size()&&a[stk.top()]>a[i]) stk.pop();
if(stk.empty()) r[i]=n+1;
else r[i]=stk.top();
stk.push(i);
}
//for(int i=1;i<=n;i++) cout<<l[i]<<" "<<r[i]<<endl;
for(int i=1;i<=n;i++) L[i]=L[l[i]]+1ll*(i-l[i])*a[i];
for(int i=n;i>=1;i--) R[i]=R[r[i]]+1ll*(r[i]-i)*a[i];
//for(int i=1;i<=n;i++) cout<<L[i]<<" "<<R[i]<<endl;
ll MaxUp=INT_MIN; int inx=-1;
for(int i=1;i<=n;i++){
ll res=L[i]+R[i]-(ll)a[i];
if(MaxUp<res){
MaxUp=res;
inx=i;
}
}
int MaxPre=a[inx],MaxSuf=a[inx];
for(int i=inx;i>=1;i--) { MaxPre=min(a[i],MaxPre); a[i]=MaxPre; }
for(int i=inx;i<=n;i++) { MaxSuf=min(a[i],MaxSuf); a[i]=MaxSuf; }
for(int i=1;i<=n;i++) printf("%d%c",a[i],i==n?'\n':' ');
return 0;
}