• 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 某一点 我好像过不去

  • 相关阅读:
    php ajax 表格排序,调整列宽,修改内容
    Jquery隐藏式评论
    还是一个鼠标点击td变成input,失去焦点更新数据库
    Jquery php 点击td变成input,修改后失去焦点发送数据
    hdu 1713 相遇周期 比较绕的最大公约,最小公倍问题
    hdu 1722 Cake (抽象出欧几里得)
    提供Webservice的地方
    实现汉字转拼音
    java 注解
    c#获取汉字的拼音首字母
  • 原文地址:https://www.cnblogs.com/wcz112/p/6344877.html
Copyright © 2020-2023  润新知