题解 [NOIP2011 提高组] 聪明的质监员
不难发现, 越大, 以及 就越小, 越小, 就越大。
所以这是一个二分答案。
考虑如何 。
观察
不难发现,乘号的前后都是区间和的形式,有因为要计算多个区间,所以想到前缀和。
对于一个二分的 ,将 的拿出来做前缀和,在计算时即可 调用。
代码:
#include<bits/stdc++.h> using namespace std; typedef long long LL; LL read() { LL sum=0,flag=1; char c=getchar(); while(c<'0'||c>'9') {if(c=='-') flag=-1; c=getchar();} while(c>='0'&&c<='9') {sum=sum*10+c-'0'; c=getchar();} return sum*flag; } const int N=2e5+10,INF=1e6+10; int n,m; int a[N],b[N]; LL s; LL w[N],v[N]; LL sumn[N],sumv[N]; LL calc(int tw) { for(int i=0;i<=n;i++) sumn[i]=sumv[i]=0; for(int i=1;i<=n;i++) { if(w[i]>=tw) { sumn[i]=sumn[i-1]+1; sumv[i]=sumv[i-1]+v[i]; } else { sumn[i]=sumn[i-1]; sumv[i]=sumv[i-1]; } } LL tot=0; for(int i=1;i<=m;i++) { tot+=(sumn[b[i]]-sumn[a[i]-1])*(sumv[b[i]]-sumv[a[i]-1]); } return tot; } LL find1() { int l=0,r=INF; while(l<r) { int mid=l+r>>1; if(calc(mid)<=s) r=mid; else l=mid+1; } return calc(r); } LL find2() { int l=0,r=INF; while(l<r) { int mid=l+r+1>>1; if(calc(mid)>=s) l=mid; else r=mid-1; } return calc(l); } int main() { cin>>n>>m>>s; for(int i=1;i<=n;i++) { cin>>w[i]>>v[i]; } for(int i=1;i<=m;i++) { cin>>a[i]>>b[i]; } LL ansa=s-find1(); LL ansb=find2()-s; cout<<min(ansa,ansb); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效