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. 3.4.2 Undefined类型【JavaScript高级程序设计第三版】

    Undefined 类型只有一个值,即特殊的 undefined.在使用 var 声明变量但未对其加以初始化时,这个变量的值就是 undefined,例如: var message; alert(me ...

  2. python——内建模块instance的学习

    python中内建函数isinstance的用法 语法:isinstance(object,type) 作用:来判断一个对象是否是一个已知的类型. 其第一个参数(object)为对象,第二个参数(ty ...

  3. POJ 1180 斜率优化DP(单调队列)

    Batch Scheduling Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 4347   Accepted: 1992 ...

  4. poj 2965 枚举+DFS

    The Pilots Brothers' refrigerator Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 25343 ...

  5. 通过aop添加日志管理

    1.使用spring 的 aop 技术切到自定义注解上,所以先创建一个自定义注解类 import java.lang.annotation.*; @Target(ElementType.METHOD) ...

  6. WPF点击不同界面上的按钮实现界面切换

    原文:WPF点击不同界面上的按钮实现界面切换 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/qq_29844879/article/details/ ...

  7. hash算法和常见的hash函数 [转]

       Hash,就是把任意长度的输入,通过散列算法,变换成固定长度的输出,该输出就是散列值. 这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能 会散列成相同的输出,而不 ...

  8. Erlang中atom的实现[转]

    转自: http://www.cnblogs.com/zhengsyao/p/3424539.html 在 Erlang 中,使用 atom 既方便又高效,我们就来看看 atom 是怎么实现的.ato ...

  9. js实现类bootstrap模态框动画

    在pc端开发,模态框是一个很常用的插件,之前一直用的第三方插件,比如bootstrap,jQuery的模态框插件,最近还用了elementUI的.但是会发现其实动画效果都差不多,那么如何去实现这样一个 ...

  10. isinstance()判断数据类型

    判断数据类型isinstance()l=[1,2,3]print(isinstance(l,list))#括号里面第一个填需要判断的数据,第二个是判断条件