BZOJ3346 : Ural1811 Dual Sim Phone
首先将边进行去重,那么有$n\geq\sqrt{m}$。
然后二分答案,转化为判定是否存在两个点它们的出边集合的并集为全集。
那么这两个点必然满足$deg_x+deg_y\geq n$。
不妨设$deg_x\geq deg_y$,那么有$deg_x\times 2\geq n$。
考虑枚举$x$,最多只会有$O(\frac{m}{n})$个$x$。
再枚举$y$,有两种判定算法:
$1.$设$f[i][j]$表示$i$是否没有指向$j$,那么只要存在$f[x][j]\ and\ f[y][j]=true$即不可行。
可以压位计算,时间复杂度$O(\frac{nm}{32})$。
$2.$枚举$y$的所有出边,通过时间戳判定是否出现在$x$中。
时间复杂度$O(\frac{m^2}{n})$。
设$S$为阈值,当$n\leq S$时用算法1,否则用算法2,则有$\frac{Sm}{32}\leq\frac{m^2}{S}$。
当$S$取$\sqrt{32m}$时,取得最优复杂度$O(m\sqrt{\frac{m}{32}})$。
总时间复杂度$O(m\log m\sqrt{\frac{m}{32}})$。
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 | #include<cstdio> #include<algorithm> const int N=10005,M=100010; int n,m,U,i,j,k,a[M],st[N],en[N],d[N],v[N],t,l,r,mid,ans; unsigned int f[2048][64]; struct E{ int x,y,z;}e[M]; inline bool cmp( const E&a, const E&b){ if (a.x!=b.x) return a.x<b.x; if (a.y!=b.y) return a.y<b.y; return a.z<b.z; } inline void read( int &a){ char c; while (!(((c= getchar ())>= '0' )&&(c<= '9' )));a=c- '0' ; while (((c= getchar ())>= '0' )&&(c<= '9' ))(a*=10)+=c- '0' ;} bool check( int mid){ if (n>2048){ for (i=0;i<n;i++){ d[i]=0; for (j=st[i];j<en[i];j++) if (e[j].z<=mid)d[i]++; } for (i=0;i<n;i++)v[i]=-1; for (i=0;i<n;i++) if (d[i]*2>=n){ for (k=st[i];k<en[i];k++) if (e[k].z<=mid)v[e[k].y]=i; for (j=0;j<n;j++) if (d[i]+d[j]>=n&&d[i]>=d[j]){ t=d[i]; for (k=st[j];k<en[j];k++) if (e[k].z<=mid&&v[e[k].y]<i)t++; if (t==n) return 1; } } } else { for (i=0;i<n;i++){ for (j=0;j<U;j++)f[i][j]=~0U; f[i][U]=0; for (j=U<<5;j<n;j++)f[i][j>>5]|=1U<<(j&31); } for (i=0;i<n;i++){ d[i]=0; for (j=st[i];j<en[i];j++) if (e[j].z<=mid)d[i]++,f[i][e[j].y>>5]^=1U<<(e[j].y&31); } for (i=0;i<n;i++) if (d[i]*2>=n){ for (j=0;j<n;j++) if (d[i]+d[j]>=n&&d[i]>=d[j]){ t=1; for (k=0;k<=U;k++) if (f[i][k]&f[j][k]){t=0; break ;} if (t) return 1; } } } return 0; } int main(){ read(n),read(m);U=(n-1)>>5; for (i=1;i<=m;i++){ read(e[i].x),read(e[i].y),read(e[i].z); e[i].x--,e[i].y--; } std::sort(e+1,e+m+1,cmp); for (i=1;i<=m;i++) if (i==1||e[i].x!=e[i-1].x||e[i].y!=e[i-1].y)e[++j]=e[i]; for (m=j,i=1;i<=m;i++)a[i]=e[i].z; std::sort(a+1,a+m+1); for (i=0,j=1;i<n;i++){ st[i]=j; while (j<=m&&e[j].x==i)j++; en[i]=j; } l=1,r=m; while (l<=r) if (check(a[mid=(l+r)>>1]))r=(ans=mid)-1; else l=mid+1; if (!ans) puts ( "No solution" ); else printf ( "%d" ,a[ans]); return 0; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步