zoukankan      html  css  js  c++  java
  • P4767 [IOI2000]邮局

    P4767 [IOI2000]邮局
    wqs 二分+四边形不等式优化 dp

    最朴素的dp是 (f_{i,j}) 表示前 (i) 个村庄设立了 (j) 个邮局的最有答案,但这样每个状态转移是 (O(V)),总复杂度 (O(V^2P))
    于是可以用 wqs 二分,每次增加一个邮局就多付出一个权值,二分这个权值即可,至于正确性大概就是一段区间内邮局放的越多,距离和减小的越少
    然后此时就 (O(Vlog w)) 了(其中 (w) 指距离),但仍可以继续优化。记录 (sum_i) 为前缀和,那么 ([l,r]) 中建立一个邮局所产生的最小距离和就是 (w(l,r)=sum_r+sum_{l-1}-sum_{mid}-sum_{mid-2}),其中 (mid=frac{l+r}{2})
    然后按四边形不等式的定义减一减就可以知道它是满足四边形不等式的,于是 wqs 二分的 check 可以用决策单调性优化,那么就做到了 (O(Vlog Vlog w))

    忘了怎么写决策队列了,一直写错,调吐了

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #define reg register
    inline int read(){
    	register int x=0;register int y=1;
    	register char c=std::getchar();
    	while(c<'0'||c>'9'){if(c=='-') y=0;c=getchar();}
    	while(c>='0'&&c<='9'){x=x*10+(c^48);c=getchar();}
    	return y?x:-x;
    }
    #define N 100006
    int n,k;
    long long a[N],sum[N];
    long long sumD,C;
    struct DP{
    	long long val;int num;
    }f[N];
    struct Q{
    	int l,r,id;
    }que[N];
    int left,right;
    inline int operator < (const DP &a,const DP &b){return a.val==b.val?a.num>b.num:a.val<b.val;}
    inline int operator <= (const DP &a,const DP &b){return a.val==b.val?a.num>=b.num:a.val<=b.val;}
    inline DP operator + (const DP &a,const DP &b){return (DP){a.val+b.val,a.num+b.num};}
    inline DP calc(reg int j,reg int i){//[j,i]
    //	if(j==i) return 0;
    //	if(j+1==i) return a[i]-a[j];
    	j++;
    	int mid=(i+j)>>1;
    	return (DP){sum[i]+sum[j-1]-sum[mid]-sum[mid-1]+(2*mid-i-j)*a[mid]+C,1}+f[j-1];
    }
    inline int find(reg int l,reg int r,int id,int cmp_id){
    	reg int mid,ans;
    	while(l<=r){
    		mid=(l+r)>>1;
    		if(calc(id,mid)<=calc(cmp_id,mid)) ans=mid,r=mid-1;
    		else l=mid+1;
    	}
    	return ans;
    }
    inline int check(){
    	f[0]=(DP){0,0};
    	left=right=0;que[0]=(Q){1,n,0};
    	for(reg int i=1;i<=n;i++){
    		while(que[left].r<i&&left<=right) left++;
    		f[i]=calc(que[left].id,i);
    		if(i==n||calc(que[right].id,n)<calc(i,n)) continue;
    		while(left<=right&&calc(i,que[right].l)<=calc(que[right].id,que[right].l)) right--;
    		if(left>right) que[++right]=(Q){i+1,n,i};
    		else{
    			int pos=find(i+1,n,i,que[right].id);
    			que[right].r=pos-1;que[++right]=(Q){pos,n,i};
    		}
    	}
    	sumD=f[n].val;
    	return f[n].num;
    }
    int main(){
    	n=read();k=read();
    	for(reg int i=1;i<=n;i++) a[i]=read(),sum[i]=sum[i-1]+a[i];
    	reg long long l=0,r=1e14,ans;
    	while(l<=r){
    		C=(l+r)>>1;
    		if(check()>=k) l=C+1,ans=sumD-k*C;
    		else r=C-1;
    	}
    //	int kk=check(ans);
    //	printf("%lld in %lld,kk=%d
    ",sumD-k*ans,ans,kk);
    	printf("%lld
    ",ans);
    //		printf("debug : %lld
    ",calc(50,1));
    	return 0;
    }
    
  • 相关阅读:
    FLEX,图标操作,xml, 通信,实例
    FLEX 合并两个XML的属性
    在内核中如何获得系统的日期和时间
    delphi中生成空格的函数
    Delphi中使用@取函数地址的问题
    vc中产生随机数
    delphi里label显示多行文本的两种方法
    360,傲游,诺顿最新版,网页溢出防护原理
    VC使用Zlib对内存流进行压缩与解压缩
    【TXPManifest控件】Delphi使用XP样式的按钮等控件
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/14555680.html
Copyright © 2011-2022 走看看