zoukankan      html  css  js  c++  java
  • CF724E

    根据题意建立流模型。
    (s->i)连接(p_i)
    (i->t)连接(s_i)
    (i->j,i<j)连接(c)
    发现由于数据范围,不太能做。
    这个模型事实上是经典的二元关系网络流。
    如果一个点被分到(s)集合则把它标为(0),分到(t)集合就标为(1)
    问题转化成:给每个点一个标号,如果(i)(0)则获得(s_i)代价,是(1)则获得(p_i)代价。
    如果存在(i<j)(i)(0)(j)(1),则代价额外加上(c)
    显然考虑dp,设(f_{i,j})表示前缀([1,i])(j)(0),后面没有填的最小费用。
    则我们就知道前面有多少个(1),代价可以轻松计算。
    由于题目空间卡,要滚动数组。
    虽然时间复杂度是(O(n^2)),但是常数小,可以过。
    考虑更为优秀的做法,用经典的贪心调整法。
    把每个数的标号初始成(0),接着考虑把一个点变成(1)
    则代价+=前面(0)个数,-=后面(1)个数,+=(p_i-s_i)
    观察发现随着一些(0)变成(1),每个位置的代价会恒定减去(c)
    如果位置(i,j)(i)(j)优,以后(i)也比(j)优。
    于是排序后贪心选即可,时间复杂度是(O(nlog_2n))
    所以这道题真的有2900难度吗...

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    #define N 1000010
    int n,c,p[N],s[N],ans,a[N],va;
    signed main(){
    	scanf("%lld%lld",&n,&c);
    	for(int i=1;i<=n;i++)
    		scanf("%lld",&p[i]);
    	for(int i=1;i<=n;i++)
    		scanf("%lld",&s[i]);
    	for(int i=1;i<=n;i++)
    		ans+=p[i];
    	for(int i=1;i<=n;i++)
    		a[i]=c*(n-i)+s[i]-p[i];
    	sort(a+1,a+n+1);
    	va=ans;
    	for(int i=1;i<=n;i++){
    		ans+=a[i]-c*(i-1);
    		va=min(va,ans);
    	}
    	printf("%lld
    ",va);
    }
    
  • 相关阅读:
    CF1070F Debate
    P3502 [POI2010]CHO-Hamsters
    CF1421A XORwice
    P2073 送花
    树链剖分边权转化为点权
    球——数学分析,模型构建
    数位dp的模版
    不要62
    智慧题——规律题
    CF551C GukiZ hates Boxes——模拟加二分
  • 原文地址:https://www.cnblogs.com/ctmlpfs/p/14880291.html
Copyright © 2011-2022 走看看