• ARC117


    ARC117 - Gateau

    题目大意:给定一个长度为(2n)的非负环序列(x_0,x_1,cdots x_{2n-1}),以及(2n)条限制,每条都是

    $forall A_i,sum_{j=0}^{n-1} x_{i+jmod 2n}ge A_i $

    求最小化(sum x_i)


    [ ]

    转化为前缀和作差之后,令人联想到差分约束,但是难以处理跨过环末的限制

    于是二分答案(s=x_{2n-1}),建立最长路图

    (forall i<n,dis_{i+n}ge dis_{i}+A_i)

    (forall ige n,dis_{i-n}ge dis_{i}+A_i-s)

    (forall i<2n-1,dis_{i+1}leq dis_i)

    那么无解的条件就是:存在正环或者求得(dis_{2n-1}>s)

    自然无法直接通过( ext{SPFA})来跑。。。

    考虑所有的边构成了一条(0-2n-1)的零链 和若干极小的二元环

    如果二元环出现正环则无解,否则任意一条最长路路径总是可以描述为

    (i<j<n , i(+n) ightarrow j(+n))

    在中间点(k)可以选择花费0的代价向后走,或者

    (k<n:k ightarrow k+n,cost=A_k)

    (kge n:k ightarrow k-n,cost=A_k-s)

    也就是在(k,k+n)之间反复横跳,由此发现一条路径就是

    (0-n-1)进行扫描,并且允许中间(pm n)横跳

    (当然这里漏掉了一个特殊边,即(dis_{n}ge dis_{n-1}),这是构成环的边)

    这样写出一个变种的( ext{Bellman Ford}),由于图的特殊性,只需要常数轮即可确定正环

    具体的,当图上不存在正环时,扫描最多经过一次环就会停止更新

    也就是这样横跳的扫描更新只会进行常数轮(2轮?)

    如果若干轮后依然在更新,说明出现了正环

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef double db;
    typedef pair <int,int> Pii;
    #define reg register
    #define mp make_pair
    #define pb push_back
    #define Mod1(x) ((x>=P)&&(x-=P))
    #define Mod2(x) ((x<0)&&(x+=P))
    #define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
    #define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
    template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
    int cmax(int &a,int b){ return a<b?a=b,1:0; }
    
    char IO;
    template <class T=int> T rd(){
    	T s=0; int f=0;
    	while(!isdigit(IO=getchar())) f|=IO=='-';
    	do s=(s<<1)+(s<<3)+(IO^'0');
    	while(isdigit(IO=getchar()));
    	return f?-s:s;
    }
    
    const int N=3e5+10,INF=1e9+10;
    
    int n;
    int A[N],dp[N];
    
    int Check(int s) {
    	rep(i,0,n-1) if(A[i]+A[i+n]-s>0) return 0;
    	rep(i,0,n*2-1) dp[i]=0;
    	dp[n*2-1]=s;
    	int f=0;
    	rep(k,0,5) { 
    		f=0;
    		rep(i,0,n-1) {
    			f|=cmax(dp[i+n],dp[i]+A[i]);
    			f|=cmax(dp[i],dp[i+n]+A[i+n]-s);
    			if(i<n-1) {
    				f|=cmax(dp[i+1],dp[i]);
    				f|=cmax(dp[i+n+1],dp[i+n]);
    			}
    		}
    		f|=cmax(dp[n],dp[n-1]);
    	}
    	if(f || dp[n*2-1]>s) return 0;
    	return 1;
    }
    
    int main() {
    	n=rd();
    	rep(i,0,n*2-1) A[i]=rd();
    	int res=-1;
    	for(int l=0,r=1.05e9,mid;l<=r;) Check(mid=(l+r)>>1)?r=mid-1,res=mid:l=mid+1;
    	printf("%d
    ",res);
    }
    
    
  • 相关阅读:
    一个程序媛小渣的自我反省--纯属吐槽
    前端常见的性能优化手段
    js的命名空间 && 单体模式 && 变量深拷贝和浅拷贝 && 页面弹窗设计
    js-signals学习以及应用
    WebGL和ThreeJs学习6--射线法确定3D空间中所选物体
    前端之js-本地存储-localStorage && IndexedDB
    HelloStruts
    实验三 敏捷开发与XP实验 20175301李锦然实验报告
    《Java》第九周学习总结
    MYCP作业
  • 原文地址:https://www.cnblogs.com/chasedeath/p/14729004.html
Copyright © 2020-2023  润新知