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. tcl之过程/函数-proc

  2. php获取设备的宽度和高度

    php获取设备的宽度和高度 如果前台没有传输当前请求的宽度和高度,我们有时候需要用php借助javascript获取屏幕的宽和高,以控制现实的样式. 代码如下: <?php /* * 获取设备宽 ...

  3. php+MySQL(存储过程) +yii2完整的增删改查

    1在MySQL中创建存储过程 a 我将添加和修改 作为 一起 ), ), ), )) BEGIN FROM t_boss_role WHERE id = _id) THEN UPDATE t_boss ...

  4. 对文件 I/O,标准 I/O 的缓冲的理解

    1.标准I/O缓冲区 要理解标准I/O,就要先知道文件I/O的业务逻辑. 下面图示为文件I/O 如执行下面的代码: write(fd, buf2, sizeof(buf2)); 图中 buf:就是bu ...

  5. 010---Django与Ajax

    预备知识: 什么是Json? 定义:json是一种轻量级的数据交换格式. 如果我们要在不同的编程语言中传递对象,就必须把对象序列化为标准格式,比如XML,但那是以往的时代,现在大多数使用序列化为jso ...

  6. urllib使用二

    urlopen方法返回一个html 对html使用info()方法返回HTTPMessage对象实例 import urllib def print_list(lists): for i in lis ...

  7. 20145202马超《Java程序设计》第十周学习总结

    一.网络编程 1.网络概述 网络编程就是在两个或两个以上的设备(例如计算机)之间传输数据.程序员所作的事情就是把数据发送到指定的位置,或者接收到指定的数据,这个就是狭义的网络编程范畴.在发送和接收数据 ...

  8. Java线程和多线程(八)——Thread Dump

    Java的Thread Dump就是列出JVM中所有激活状态的线程. Java Thread Dump Java Thread Dump在分析应用性能瓶颈和死锁的时候,是非常有效的. 下面将介绍多种不 ...

  9. cocos2d-x 3.0 Node与Node层级结构

    节点解释: 节点是场景图的基本元素.场景图的基本元素必须是节点对象或者是节点对象的子类. 其中主要可以看到Layer.MenuItem.Scene.Sprite.TMXTiledMap(解析and渲染 ...

  10. MySQL之查询性能优化(一)

    为什么查询速度会慢 通常来说,查询的生命周期大致可以按照顺序来看:从客户端,到服务器,然后在服务器上进行解析,生成执行计划,执行,并返回结果给客户端.其中“执行”可以认为是整个生命周期中最重要的阶段, ...