题目传送门(内部题46)
输入格式
第一行$3$个整数$n,m,t$。
第二行$n$个整数,表示$P_i$。
接下来$m$行每行两个整数,表示$L_i,R_i$。
输出格式
一行一个整数表示答案。
样例
样例输入:
3 3 2
6 2 5
1 1
2 2
3 3
样例输出:
11
数据范围与提示
样例解释:
最优方案为使用$2$次特殊加热器,$4$次$1$号加热器,$3$次$3$号加热器。
数据范围:
对于前$20\%$的数据:$t\geqslant n$
对于另$30\%$的数据:$P_i\leqslant 30$
对于所有数据:
$1\leqslant n,m,t\leqslant {10}^5$
$1\leqslant L_i,R_i\leqslant n$
$1\leqslant P_i\leqslant {10}^7$
题解
首先,如果你不傻,特殊加热器肯定是在一开始使用。
然而随着我们使用次数的增加,普通加热器所减少的费用也越来越小,所以这是一个上凸函数,所以我们考虑三分使用次数。
剩下的贪心即可。
时间复杂度:$\Theta(n\log_{1.5}(\max(P_i)))$。
期望得分:$100$分。
实际得分:$100$分。
代码时刻
#include<bits/stdc++.h> using namespace std; struct rec{int L,R;}e[100001]; int n,m; long long t; int P[100001]; int cnt[100001]; long long ans=1LL<<60; int h[100001],tag[100001]; long long judge(int x) { for(int i=1;i<=n;i++)h[i]=max(0,P[i]-x); long long res=x*t; int flag=0; for(int i=1;i<=n;i++) { flag-=tag[i]; tag[i]=0; h[i]=max(0,h[i]-flag); res+=h[i]; flag+=h[i]; tag[cnt[i]+1]+=h[i]; } return res; } int main() { scanf("%d%d%lld",&n,&m,&t); for(int i=1;i<=n;i++)cnt[i]=-1; for(int i=1;i<=n;i++)scanf("%d",&P[i]); for(int i=1;i<=m;i++) { scanf("%d%d",&e[i].L,&e[i].R); cnt[e[i].L]=max(cnt[e[i].L],e[i].R); } int lft=0,rht=0; for(int i=1;i<=n;i++) { if(cnt[i-1]>=i) { rht=max(rht,cnt[i]); cnt[i]=rht; } if(cnt[i]==-1)lft=max(lft,P[i]); } rht=10000000; while(lft<=rht) { int mid=(lft+rht)>>1; long long flagl=judge(mid),flagr=judge(mid+1); if(flagl>=flagr) { lft=mid+1; ans=min(ans,flagr); } else { rht=mid-1; ans=min(ans,flagl); } } printf("%lld",ans); return 0; }
rp++
原文地址:https://www.cnblogs.com/wzc521/p/11551339.html
时间: 2024-11-08 03:51:55