xjoi 省选训练23_B
这场我tm 爆零了!!!!!
发现这题是一个基环树森林 拓扑排序去掉 不在环上的节点以后 只剩下一个环
那么这题就成了 环上的覆盖问题
算法1: 倍增 嗯。。。我好想不会写
算法2: 选取k个点 每一次 走k个点 那么每一次 就只会走 [n/k]步 可以先预处理出每一步 走了以后 你能走到哪里
那么对于每一个环 我们只需要 进行O(n) 就可以做到 这个环的最小覆盖 可惜我比较NAIVE 没有写这个东西
算法3: 真不好意思 这个是最烙算法 我还坑害了我边上的z1j1n1大爷 捂脸熊
发现以前做过的一道题叫做——出纳员的雇佣 由于以前比较naive 写的是枚举答案 如果写成二分 并且 用dfs判判负环
(要打时间戳) 就可以O(玄学) (据信 复杂度是(O(logN*N))) 加个O2 就可以过了爆零这题辣!!
1 #pragma GCC optimize (2) 2 #include <bits/stdc++.h> 3 #define N 500010 4 #define inf 0x7fffffff 5 using namespace std; 6 7 inline int read() 8 { 9 int x=0,f=1;char ch=getchar(); 10 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 11 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 12 return x*f; 13 } 14 int n,k,ee,st[N],d[N],sign[N],ans,fa[N]; 15 int ned[N],emp[N]; 16 struct cirle_solve_the_problem 17 { 18 struct edge{ 19 int v,w,next; 20 }vs[N*6]; 21 int st[N],ee,k,dist[N],cnt[N],vis[N],len,dis[N],flag; 22 queue <int> q; 23 void addedge(int u,int v,int w) 24 { 25 vs[++ee].v=v;vs[ee].w=w; 26 vs[ee].next=st[u];st[u]=ee; 27 } 28 void dfs(int rt,int pr){ 29 vis[rt]=pr; 30 for(int i=st[rt];i;i=vs[i].next){ 31 if(dis[vs[i].v]>dis[rt]+vs[i].w){ 32 if(vis[vs[i].v]==pr){flag=1;return;} 33 dis[vs[i].v]=dis[rt]+vs[i].w; 34 dfs(vs[i].v,pr);if(flag) return ; 35 } 36 }vis[rt]=0; 37 } 38 bool check(int pr){ 39 flag=0; 40 for(int i=0;i<=len;i++) dis[i]=10000000; 41 for(int i=0;i<=len;i++) {dfs(i,pr); 42 if(flag) return 1;} 43 return 0; 44 } 45 void graph(int lim){ 46 ee=0;for(int i=0;i<=len;i++) st[i]=0; 47 for(int i=1;i<=len;i++){ 48 addedge(i,i-1,0); 49 addedge(i-1,i,emp[i]); 50 } 51 for(int i=k;i<=len;i++) 52 addedge(i,i-k,-ned[i]); 53 for(int i=1;i<k;i++) 54 addedge(i,i+len-k,lim-ned[i]); 55 addedge(len,0,-lim); 56 } 57 bool spfa(int lim,int pr){ 58 if(n>5000)return 1; 59 queue <int> q; 60 for(int i=0;i<=len;i++) dist[i]=inf; 61 q.push(len);dist[len]=0;vis[len]=pr; 62 while(!q.empty()){ 63 int lx=q.front();q.pop(); 64 for(int i=st[lx];i;i=vs[i].next) 65 if(dist[lx]+vs[i].w<dist[vs[i].v]){ 66 dist[vs[i].v]=dist[lx]+vs[i].w; 67 if(vis[vs[i].v]!=pr) 68 q.push(vs[i].v),vis[vs[i].v]=pr; 69 } 70 vis[lx]=0; 71 } 72 if(dist[0]>=-lim) return 1;return 0; 73 } 74 int cirle_solve(int a,int b) 75 { 76 k=a;len=b; 77 int r=len/k+1,nn=0; 78 for(int i=1;i<=len;i++) nn+=(ned[i]>0); 79 if(k>=len) return (nn)? 1:0; 80 if(!nn) return 0; int l=0,ans=0x7fffffff; 81 while(l<=r) 82 { 83 int mid=(l+r)>>1; 84 graph(mid); 85 if(!check(mid)&&spfa(mid,mid)) r=mid-1,ans=min(ans,mid); 86 else l=mid+1; 87 } 88 return ans; 89 } 90 }T; 91 void pre() 92 { 93 queue <int> q; while(!q.empty()) q.pop(); 94 for(int i=1;i<=n;i++) if(!d[i]) q.push(i); 95 sign[1]=k+1; 96 while(!q.empty()) 97 { 98 int lx=q.front(); q.pop(); 99 if(!sign[lx]) sign[lx]=k,ans++; 100 int now=lx;d[fa[now]]--; 101 if(!d[fa[now]]) q.push(fa[now]); 102 sign[fa[now]]=max(sign[now]-1,sign[fa[now]]); 103 } 104 } 105 void deal() 106 { 107 for(int i=1;i<=n;i++) 108 { 109 if(d[i]) 110 { 111 int now=i; d[now]=0; int len=1; 112 if(!sign[now]) ned[len]=1; 113 else ned[len]=0, 114 sign[fa[now]]=max(sign[now]-1,sign[fa[now]]); emp[len]=1; len++; 115 for(int j=fa[now];j!=now;j=fa[j],len++) 116 { 117 emp[len]=1; d[j]=0; 118 if(!sign[j]) ned[len]=1; 119 else ned[len]=0,sign[fa[j]]=max(sign[j]-1,sign[fa[j]]); 120 } 121 len=1; 122 if(!sign[now]) ned[len]=1; 123 else ned[len]=0, 124 sign[fa[now]]=max(sign[now]-1,sign[fa[now]]); emp[len]=1; len++; 125 for(int j=fa[now];j!=now;j=fa[j],len++) 126 { 127 emp[len]=1; d[j]=0; 128 if(!sign[j]) ned[len]=1; 129 else ned[len]=0,sign[fa[j]]=max(sign[j]-1,sign[fa[j]]); 130 } 131 ans+=T.cirle_solve(k,len-1); 132 } 133 } 134 135 } 136 int main() 137 { 138 //freopen("B_small.in","r",stdin); 139 n=read();k=read(); 140 for(int i=1;i<=n;i++) 141 { 142 int a=read(),b=read(); 143 fa[a]=b; d[b]++; 144 } 145 pre(); 146 deal(); 147 cout<<ans<<endl; 148 return 0; 149 }
不好意思 我太菜了 这份代码TLE 96 某一点 我好像过不去