Codeforces 246C Little Girl And Maximum 差分

来源:互联网 发布:灭蚊激光炮淘宝 编辑:程序博客网 时间:2024/05/14 03:19

点击打开链接

题意:n个数,m次询问 n,m<=1e5 问初始时如何打乱数组的顺序 使得查询的累加和最大?

最后的累加和可以写为:ans=segma(a[i]*f[i])

每次询问l,r时 如何快速计算f? 
用线段树区间更新使f[l]~f[r]同时加上1,最后单点查询计算出f,比较麻烦
利用差分,每次更新时:c[l]++,c[r+1]-- 最后计算i的前缀和,即可求出i被包含在多少条线段(询问)中啦 
ai<aj bi<bj;
因为a[i]·b[j]+a[j]·b[i]-a[i]·b[i]-a[j]·b[j] = b[j]·(a[i]-a[j])+b[i]·(a[j]-a[i])=(b[j]-b[i])*(a[i]-a[j])<=0.
ans尽量大则大的a[i]和大的f[i]相乘即可 

#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>using namespace std;typedef long long ll;const int N=2e5+20;const ll mod=19999997; ll a[N],f[N],c[N];// f[i] 第i个元素被查询到的次数int n,m;int main(){  while(cin>>n>>m)  {  memset(c,0,sizeof(c));  for(int i=1;i<=n;i++)  scanf("%I64d",&a[i]);while(m--){int l,r;scanf("%d%d",&l,&r);f[l]++;//差分 f[r+1]--; }f[0]=0;for(int i=1;i<=n;i++)f[i]=f[i]+f[i-1];//不包含i的线段k,计算前缀和时被消去,(.lk..rk.l..i..r.. )sort(f+1,f+1+n);sort(a+1,a+1+n);ll ans=0;for(int i=1;i<=n;i++){ans+=a[i]*f[i];} cout<<ans<<endl;}return 0;}


0 0