题目链接
B. Different Rules
题意:现有n个人参加两轮的比赛,每次比赛每个人都有一个排名,最终的排名就是两次排名的和,数字小的在前面,
注意:不会出现两次比赛都一样的情况
做法:排名靠前的简单,就是x+y-1,注意排名不要超过n(被这个点wa两发), 排名靠后呢?
假设 这个人 两次排名 是x,y
那么就是使得尽量多的人排名<=x+y 那就是 两列两种情况取其中一种即可
(x-1 y+1) (x+1 ,y-1)
(x-2 y+2) (x+2 ,y-2)
(x-3 y+3) (x+3 ,y-3)
.... .....
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
int a[5];
int main()
{
int _;cin>>_;while(_--)
{
int n,x,y;
cin>>n>>x>>y;
if(x>y) swap(x,y);
int ans=0;
int t=max(0,n-y-1);//y后面有多少个可以给x的前面
int mi=min(x-1,t);//取个最小值
int t1=x-1-mi;
t=max(0,n-x-1);//x后面有多少个可以给y前面
mi=min(y-1,t);//取个最小值
int t2=y-1-mi;
mi=max(t1,t2);//两种情况取个最大值
int ans2=min(n,x-1+y);//注意不要超过n
mi=min(mi+1,n);
printf("%d %d\n",mi,ans2);
}
}
C2. Skyscrapers (hard version)
题意:给你n个建筑最高能修 的高度,现在你要构造一个凸字形的建筑,问如何分布高度 使得总高度最大。
做法:单调栈 正着一遍 反着一遍就可以了
扫描二维码关注公众号,回复:
10150435 查看本文章
正着:pre[i]前i个保持递增序列的最大前缀和
反着:last[i] 后i个保持递减序列的最大后缀和
然后O(n)枚举下 找到和最大的那个点即可。
注意还需要并查集维护下当前下标i 影响的最左边的那个下标位置,例如 5 6 2 那么pre[3] 3这个下标就会影响至1 变成2 2 2 使得pre[3]=6
那么此时 1 2 3 就变成一样的点了。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=5e5+10;
ll a[N],n,ans[N],pre[N],last[N],len[N],l1[N];
int fa[N];
int main()
{
cin>>n;
for(int i=1;i<=n;++i){
scanf("%lld",&a[i]);
len[i]=1;
l1[i]=1;
fa[i]=i;
}
stack<int>sta;
sta.push(1);
pre[1]=a[1];
for(int i=2;i<=n;++i){
if(sta.size()&&a[i]>=a[sta.top()]) sta.push(i),pre[i]=pre[i-1]+a[i];
else{
int id=i;
while(sta.size()&&a[i]<a[sta.top()]) l1[i]+=l1[sta.top()],id=fa[sta.top()],sta.pop();
sta.push(i);
fa[i]=id;
pre[i]=l1[i]*a[i]+pre[id-1];
}
}
last[n]=a[n];
while(sta.size()) sta.pop();
sta.push(n);
rep(i,1,n) fa[i]=i;
for(int i=n-1;i;--i){
if(sta.size()&&a[i]>=a[sta.top()]) sta.push(i),last[i]=last[i+1]+a[i];
else{
int id=i;
while(sta.size()&&a[i]<a[sta.top()]) id=fa[sta.top()],len[i]+=len[sta.top()],sta.pop();
sta.push(i);
fa[i]=id;
// if(i==5){
// printf("i:%d len[i]:%lld id:%d\n",i,len[i],id);
// }
last[i]=a[i]*len[i]+last[id+1];
}
}
ll sum=0,id=0;
for(int i=1;i<=n;++i){
if(pre[i-1]+last[i]>sum){
sum=pre[i-1]+last[i];
id=i;
}
}
//rep(i,1,n) printf("i:%d pre:%lld\n",i,pre[i]);
//for(int i=n;i;--i) printf("i:%d las:%lld\n",i,last[i]);
//printf("id:%d\n",id);
//printf("pre:%lld last:%lld\n",pre[4],last[5]);
ans[id]=a[id];
for(int i=id-1;i>=1;--i){
ans[i]=min(ans[i+1],a[i]);
}
for(int i=id+1;i<=n;++i){
ans[i]=min(ans[i-1],a[i]);
}
rep(i,1,n) printf("%lld ",ans[i]);
}
/*
7
7 2 5 6 7 6 5
7
7 6 5 2 5 6 7
ans:33
*/