BZOJ 4078: [Wf2014]Metal Processing Plant
4078: [Wf2014]Metal Processing Plant
Time Limit: 100 Sec Memory Limit: 128 MBSubmit: 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
4 5 0 2
1 3 7
2 0
4
Sample Output
4
HINT
Source
分析:
貌似TLE了两个下午QAQ...
考虑最暴力的方法,枚举s1和s2的最大值,然后判断是否合法,判断的时候就是一个2-SAT问题,然后发现貌似s1确定的时候s2具有单调性,可以二分,然而复杂度还是很大...
所以考虑剪枝(貌似也可以用什么压位算法...然而不想学...),我们从大到小枚举s1,然后把不合法的边都连起来,发现如果不是一个二分图了,那么就可以停止枚举了...
貌似玄学复杂度...感觉这个剪枝很机智...
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | #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
【推荐】FFA 2024大会视频回放:Apache Flink 的过去、现在及未来
【推荐】中国电信天翼云云端翼购节,2核2G云服务器一口价38元/年
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· [杂谈]如何选择:Session 还是 JWT?
· 硬盘空间消失之谜:Linux 服务器存储排查与优化全过程
· JavaScript是按顺序执行的吗?聊聊JavaScript中的变量提升
· [杂谈]后台日志该怎么打印
· Pascal 架构 GPU 在 vllm下的模型推理优化
· WinForm 通用权限框架,简单实用支持二次开发
· 硬盘空间消失之谜:Linux 服务器存储排查与优化全过程
· 如何为在线客服系统的 Web Api 后台主程序添加 Bootstrap 启动页面
· 面试官:DNS解析都整不明白,敢说你懂网络?我:嘤嘤嘤!
· Fleck:一个轻量级的C#开源WebSocket服务端库