[二分] Jzoj P3205 Dual-SIM Phone
题解
- 看到最大值最小,无脑二分先(不管有没有用)
- 考虑现将代价排序,然后二分一个代价mid,显然我们要使所有的代价都小于mid而且要可以选出两个使得所有运营商都可以打
- 然后我们先把代价都小于mid的都标记一下,将每个运营商的出度求出来(也就是能打到的最多运营商)
- 然后将其排序,那么这样的话,我们就能枚举两个运营商判断其能打的运营商是否等于n就好了
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <bitset> 4 #include <cstring> 5 #include <algorithm> 6 #define N 10010 7 using namespace std; 8 bitset<N> Q[N],P; 9 struct edge{ int x,y,v; }e[N*10],a[N]; 10 int n,m,k,p[N*10],l[N]; 11 bool cmp(edge a,edge b) { return a.x<b.x; } 12 bool check(int x) 13 { 14 memset(l,0,sizeof(l)); 15 for (int i=1;i<=n;i++) Q[i].reset(); 16 for (int i=1;i<=k;i++) if (e[i].v<=x) l[e[i].x]++,Q[e[i].x][e[i].y]=1; 17 for (int i=1;i<=n;i++) a[i].x=l[i],a[i].y=i; 18 sort(a+1,a+n+1,cmp); 19 for (int i=n;i&&a[i].x*2>=n;i--) 20 for (int j=i-1;j&&a[i].x+a[j].x>=n;j--) 21 { 22 P=Q[a[i].y]|Q[a[j].y]; 23 if (P.count()==n) return 1; 24 } 25 return 0; 26 } 27 int main() 28 { 29 scanf("%d%d",&n,&k); 30 for (int i=1;i<=k;i++) scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].v),p[i]=e[i].v; 31 sort(p+1,p+k+1); int l=1,r=k; 32 while (l<r-1) 33 { 34 int mid=l+r>>1; 35 if (check(p[mid])) r=mid; else l=mid+1; 36 } 37 if (check(p[l])) printf("%d",p[l]); else if (check(p[r])) printf("%d",p[r]); else printf("No solution"); 38 }