赞
踩
所谓wqs,就是windwhisper说:“qs”
(逃)
很神奇的科技。
四两拨千斤的解决一些本来可能不太好解决的问题。
经典模型:有若干个物品,要求选出 m m m 个,选的时候带有限制,求最优的方案。
这个正常 dp 常常需要加一维记录个数,复杂度
O
(
n
2
)
O(n^2)
O(n2) 难以通过。
设
f
(
x
)
f(x)
f(x) 表示选
x
x
x 个元素的最优答案,那么 wqs 二分使用的前提是
f
(
x
)
f(x)
f(x) 具有凸性。
换句话说,所有的点
(
i
,
f
(
i
)
)
(i,f(i))
(i,f(i)) 共同形成一个凸包。
(以下以上凸包为例,下凸包同理)
考虑对这个凸包做一条斜率为
k
k
k 的切线,切于点
(
x
,
f
(
x
)
)
(x,f(x))
(x,f(x))。
如何找到这条切线呢?
注意到,切线在
y
y
y 轴上的截距必然是最大的。
设截距
D
=
f
(
x
)
−
k
x
D=f(x)-kx
D=f(x)−kx,我们就使要对于所有
x
x
x,求出
D
D
D 的最大值。
注意到
−
k
x
-kx
−kx 这一项,那么我们只需要把每个物品的价值减去
k
k
k,然后直接求最大值即可。
如果这个切点不在我们需要的
m
m
m 处,由于这个切点横坐标是随
k
k
k 单调的,所以我们可以二分寻找,直到可以切到
m
m
m 的
k
k
k 为止。
找到正确的
k
k
k,求出对应的
D
D
D 后,
f
(
x
)
f(x)
f(x) 就等于
D
+
k
x
D+kx
D+kx,也就不难得到了。
一些细节:
- 切点很坐标关于 k k k 的函数并不是连续的,因此可能需要最后一步强制选 m m m 个来算出答案,对应的,我们也最好把恰好取 m m m 个的情况归到大于 m m m 个的那边。
- 如果我们把相等的情况归于大于,那么在物品权值相等的时候我们就需要把特殊物品优先,这样如果我们强制抛弃才不会出现选不够 m m m 个的情况。
给出一张图,求出在满足 1 1 1 的度数恰好为 m m m 的情况下的最小生成树。
显然最小生成树权值关于
1
1
1 的度数是一个凸函数。
那么我们就二分一个
k
k
k,令所有和
1
1
1 相连的边权值减去
k
k
k,跑一边最小生成树,看
1
1
1 的度数和
m
m
m 大小关系即可。
#include<bits/stdc++.h> using namespace std; #define ll long long #define ull unsigned long long #define debug(...) fprintf(stderr,__VA_ARGS__) #define ok debug("OK\n") inline ll read(){ ll x(0),f(1);char c=getchar(); while(!isdigit(c)){if(c=='-') f=-1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();} return x*f; } const int N=1e6+100; const int M=1e6+100; const int mod=1e9; int n,m,s,k; struct edge{ int x,y,w,op,id; }e[N]; bool cmp(edge x,edge y){ if(x.w!=y.w) return x.w<y.w; else return x.op>y.op; } int fa[N]; int find(int x){ return x==fa[x]?x:fa[x]=find(fa[x]); } ll ans; int q[N],num; int check(int val,int op=0){ ans=0; //printf("\nval=%d op=%d\n",val,op); for(int i=1;i<=m;i++){ e[i].op?e[i].w+=val:0; } for(int i=1;i<=n;i++) fa[i]=i; sort(e+1,e+1+m,cmp); int o=n,d=0; for(int i=1;o>1&&i<=m;i++){ int x=find(e[i].x),y=find(e[i].y); //printf("(%d %d) val=%d\n",e[i].x,e[i].y,e[i].w); if(x==y) continue; if(op&&d==k&&e[i].op) continue; //printf(" ok\n"); --o;d+=e[i].op; fa[x]=y; ans+=e[i].w; if(op) q[++num]=e[i].id; } ans-=d*val; if(o>1){ printf("-1\n");exit(0); } for(int i=1;i<=m;i++){ e[i].op?e[i].w-=val:0; } return d; } signed main(){ #ifndef ONLINE_JUDGE //freopen("a.in","r",stdin); //freopen("a.out","w",stdout); #endif n=read();m=read();s=1;k=read(); for(int i=1;i<=m;i++){ int x=read(),y=read(),w=read(); e[i]=(edge){x,y,w,x==s||y==s,i}; } int st=-4e4,ed=4e4; while(st<ed){ int mid=(st+ed+1)>>1,num=check(mid); if(num>=k) st=mid; else ed=mid-1; //printf("mid=%d num=%d\n",mid,num); } if(st==-4e4) printf("-1\n"); else{ int nm=check(st,1); //printf("st=%d num=%d\n",st,num); printf("%d\n",num); for(int i=1;i<=num;i++) printf("%d ",q[i]); } return 0; } /* 5 6 1 3 1 2 2 1 4 5 1 5 5 1 3 2 3 5 4 2 4 4 */
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。