4078: [Wf2014]Metal Processing Plant

Time Limit: 100 Sec  Memory Limit: 128 MB
Submit: 86  Solved: 20
[Submit][Status][Discuss]

Description

定义集合S的价值D(S)为:

 
现在给你n个元素,并给出其中任意两个元素之间的d(i,j)值,要你将这些元素划分成两个集合A、B。求min{D(A)+D(B)}。
注:d(i,j)=d(j,i)。

Input

输入数据的第一行是一个整数n,代表元素个数。

之后n-1行描述的是d(i,j),这部分里,第i行包含n-i个整数,第i行第j列的整数代表的是d(i,i+j)。

Output

输出只有一行,一个整数,代表min{D(A)+D(B)}。

Sample Input

5
4 5 0 2
1 3 7
2 0
4

Sample Output

4

HINT

Source

分析:

貌似TLE了两个下午QAQ...

考虑最暴力的方法,枚举$s1$和$s2$的最大值,然后判断是否合法,判断的时候就是一个$2-SAT$问题,然后发现貌似$s1$确定的时候$s2$具有单调性,可以二分,然而复杂度还是很大...

所以考虑剪枝(貌似也可以用什么压位算法...然而不想学...),我们从大到小枚举$s1$,然后把不合法的边都连起来,发现如果不是一个二分图了,那么就可以停止枚举了...

貌似玄学复杂度...感觉这个剪枝很机智...

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<ctime>
//by NeighThorn
#define inf 0x3f3f3f3f
using namespace std; const int maxn=400+5,maxm=200000+5; int id;
int lala,fa[maxn],co[maxn];
int C,tim,top,mp[maxn],dfn[maxn],low[maxn],stk[maxm],instk[maxn];
int n,s1,s2,ans,cnt,len,w[maxn][maxn],hd[maxn],to[maxm],nxt[maxm]; struct M{ int x,y,v; inline M(){}; M(int a,int b,int c){
x=a,y=b,v=c;
} friend bool operator < (M a,M b){
if(a.v!=b.v)
return a.v>b.v;
if(a.x!=b.x)
return a.x>b.x;
return a.y>b.y;
} }e[maxm]; inline int read(void){
char ch=getchar();int x=0;
while(!(ch>='0'&&ch<='9')) ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
} inline void add(int x,int y){
to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++;
} inline void tarjan(int x){
low[x]=dfn[x]=++tim;stk[++top]=x;instk[x]=1;
for(int i=hd[x];i!=-1;i=nxt[i]){
if(!dfn[to[i]])
tarjan(to[i]),low[x]=min(low[x],low[to[i]]);
else if(instk[to[i]])
low[x]=min(low[x],dfn[to[i]]);
}
if(dfn[x]==low[x]){
C++;int tmp;
do{
tmp=stk[top--],instk[tmp]=0;mp[tmp]=C;
}while(tmp!=x);
}
} inline bool check(void){
cnt=C=tim=top=0;
memset(mp,0,sizeof(mp));
memset(hd,-1,sizeof(hd));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(instk,0,sizeof(instk));
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++){
if(w[i][j]>s1)
add(i<<1,j<<1|1),add(j<<1,i<<1|1);
if(w[i][j]>s2)
add(i<<1|1,j<<1),add(j<<1|1,i<<1);
}
for(int i=2;i<=(n<<1|1);i++)
if(!dfn[i]) tarjan(i);
for(int i=1;i<=n;i++)
if(mp[i<<1]==mp[i<<1|1])
return false;
return true;
} inline int find(int x){
if(fa[x]==x)
return x;
int fx=find(fa[x]);
co[x]^=co[fa[x]];
return fa[x]=fx;
} inline int calc(int x){
int l=0,r=x,res=-1;
while(l<=r){
int mid=(l+r)>>1;s2=mid;
if(check())
r=mid-1,res=mid;
else
l=mid+1;
}
return res;
} signed main(void){
n=read();ans=inf;
if(n<=2) return puts("0"),0;
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
w[i][j]=w[j][i]=read(),e[++lala]=M(i,j,w[i][j]);
sort(e+1,e+lala+1);for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1,x,y,fx,fy,res;i<=lala;i++){
s1=e[i].v;x=e[i].x,y=e[i].y,fx=find(x),fy=find(y);
if(fx!=fy){
res=calc(s1);
if(res!=-1) ans=min(ans,s1+res);
co[fx]=co[x]^co[y]^1;fa[fx]=fy;
}
else if(co[x]==co[y]){
res=calc(s1);
if(res!=-1) ans=min(ans,res+s1);
break;
}
}
printf("%d\n",ans);
return 0;
}

By NeighThorn

BZOJ 4078: [Wf2014]Metal Processing Plant的更多相关文章

  1. BZOJ 4078: [Wf2014]Metal Processing Plant [放弃了]

    以后再也不做$World Final$的题了................ 还我下午 bzoj上TLE一次后就不敢交了然后去uva交 Claris太神了代码完全看不懂 还有一个代码uva上竟然WA了 ...

  2. 【刷题】BZOJ 4078 [Wf2014]Metal Processing Plant

    Description 定义集合S的价值D(S)为: 现在给你n个元素,并给出其中任意两个元素之间的d(i,j)值 要你将这些元素划分成两个集合A.B. 求min{D(A)+D(B)}. 注:d(i, ...

  3. bzoj 4078: [Wf2014]Metal Processing Plant【二分+2-SAT+枚举+并查集】

    枚举从大到小s1,二分s2(越大越有可能符合),2-SAT判断,ans取min 思路倒是挺简单的,就是二分的时候出了比较诡异的问题,只能二分s2的值,不能在数组上二分... 有个优化,就是当不是二分图 ...

  4. BZOJ4078 : [Wf2014]Metal Processing Plant

    设$D(A)\leq D(B)$,从小到大枚举$D(A)$,双指针从大到小枚举$D(B)$. 那么对于权值不超过$D(A)$的边,可以忽略. 对于权值介于$(D(A),D(B)]$之间的边,需要满足那 ...

  5. Codeforces Gym 101221G Metal Processing Plant(2-SAT)

    题目链接 题意:有 \(n\) 个元素,第 \(i\) 个数与第 \(j\) 个数之间有一个权值 \(d_{i,j}\),\(d(i,j)=d(j,i)\). 定义函数 \(D(S)=\max\lim ...

  6. BZOJ4078 WF2014Metal Processing Plant(二分答案+2-SAT)

    题面甚至没给范围,由数据可得n<=200.容易想到二分答案,暴力枚举某集合的价值,2-SATcheck一下即可.这样是O(n4logn)的. 2-SAT复杂度已经是下界,考虑如何优化枚举.稍微改 ...

  7. bzoj 4080: [Wf2014]Sensor Network【瞎搞+随机化】

    参考:https://blog.csdn.net/YihAN_Z/article/details/73380387 一点都不想写正解.jpg random_shuffle一下然后贪心的加点,和ans取 ...

  8. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  9. Processing Images

    https://developer.apple.com/library/content/documentation/GraphicsImaging/Conceptual/CoreImaging/ci_ ...

随机推荐

  1. 【转载】最长回文字符串(manacher算法)

    原文转载自:http://blog.csdn.net/lsjseu/article/details/9990539 偶然看见了人家的博客发现这么一个问题,研究了一下午, 才发现其中的奥妙.Stupid ...

  2. java中的运算(2013-05-03-bd 写的日志迁移

    // ++自加 --自减 int a=9; a++; // a=a+1; System.out.println(a); // a=10 a--; // a=a-1 System.out.println ...

  3. win8电脑字体出现方格的解决方法

    一般电脑出现乱码有几种可能,最常见的可能就是电脑字体的丢失,其次就是电脑字体被病毒所损坏,因此,首先我们要做的就是下载字体并进行安装. 下载 simsun.tcc点击安装,如果电脑字体依然是这种情况( ...

  4. [CQOI2007]余数求和 (分块+数学

    题目描述 给出正整数n和k,计算G(n, k)=k mod 1 + k mod 2 + k mod 3 + … + k mod n的值,其中k mod i表示k除以i的余数.例如G(10, 5)=5 ...

  5. DFS初级剪枝及心得

    关于DFS心得: 1.利用结构体,记录mark和题目要求的基本属性. 2.用到递归,使用递归时注意要设置出口,即符合要求时return,注意对递归的理解,对于不同情况可能要传递不同的参数,但出口都是一 ...

  6. Oozie 实战之 Hive

    1.编辑job.propertiers nameNode=hdfs://cen-ubuntu.cenzhongman.com:8020 jobTracker=localhost:8032 queueN ...

  7. HDU 4405 Aeroplane chess(期望dp)

    Aeroplane chess Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

  8. 跟着学!教你开发第一个Java程序

    今天我们的目标是开发人生中的第一个Java程序,虽然可能会很简单,但是这小小的一步却是跨入IT行业的一大步!下面我们来一起来仔细的了解开发的流程. 准备工作 1,作为一名准程序猿自备一台电脑那是必不可 ...

  9. appium+python的APP自动化(2)

    上节说到安卓上的测试环境都安装好了,这个时候要安装python了 1python的安装 https://www.python.org/15官网下载python2.7(3.0以上也行,个人爱好),安装也 ...

  10. net对象的克隆

    class Person { public string name; public List<string> hobby; } void main() { Person p1 = new ...