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

时间: 2024-12-09 08:22:27

xjoi 省选训练23_B的相关文章

XJOI网上同步训练DAY2 T1

[问题描述] 为了迎接校庆月亮中学操场开始施工.不久后操场下发现了很多古墓这些古墓中有很多宝藏.然而学生们逐渐发现自从操场施工之后学校的运气就开始变得特别不好.后来经过调查发现古墓下有一个太守坟由于操场施工惊动了太守所以学校的运气才会特别不好. 你——月亮中学的学生之一为了拯救学校在梦中和太守进行了沟通.太守说“只要你能解决这个问题我就保佑你们从此事事顺心.你看操场下的古墓中有 个宝藏编号为 到 .现在你必须选择宝藏的一个集合可以不选或者全选.我有两种条件第一种条件有 个每一种条件形如‘如果你选

xjoi省选模拟赛_14

T1 发现 对于当前 投出 奇数次向上的概率为 p 那么 若加入一个 pi=0.5 的骰子 发现  p奇 +1=p奇 * 0.5+p偶 * 0.5 = p偶+1  也就是说 只要方案中存在一个 p=0.5 的骰子 这个方案必然合法  : 1 #include <bits/stdc++.h> 2 #define N 100 3 #define eps 1e-7 4 using namespace std; 5 typedef long double ldb; 6 int t,n; 7 ldb A

XJOI网上同步训练DAY2 T2

[问题描述] 火车司机出秦川跳蚤国王下江南共价大爷游长沙.每个周末勤劳的共价大爷都会开车游历长沙市. 长沙市的交通线路可以抽象成为一个 个点 条边的无向图点编号为 到 任意两点间均存在恰好一条路径显然两个点之间最多也只会有一条边相连.有一个包含一些点对 的可重集合 共价大爷的旅行路线是这样确定的每次他会选择 中的某一对点 并从 出发沿着唯一路径到达 . 小L是共价大爷的脑残粉为了见到共价大爷的尊容小L决定守在这张图的某条边上等待共价大爷的到来.为了保证一定能见到他显然小L必须选择共价大爷一定会经

XJOI网上同步训练DAY1 T3

思路:一开始看到这题的时候想DP,可是发现貌似不行..因为有前缀也有后缀,而且有的后缀会覆盖到现在的前缀,这就不满足无后效性了啊! 但是有个很巧妙的思路:如果我们知道a[i]的最大值,那么p的数量和q的数量也确定了.所以序列长度也确定了,设m为序列长度. 而且对于每个a[i]都代表了一个固定数量的p和q和长度. 因此,长度大于m/2的前缀,我们可以用总的p和总的q减去它,转换成小于等于m/2长度的前缀后缀. 这样我们可以设计DP为f[i][j][k],代表从左往右i个中有j个p,从右往左i个有k

XJOI网上同步训练DAY6 T2

思路:记得FJ省队集训好像有过这题,可是我太弱了,根本不懂T_T 1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 int n,m; 7 double f[1005][1005]; 8 int pd[1005][1005]; 9 int read(){ 10 int t=0,f=1;char c

XJOI网上同步训练DAY6 T1

思路:考试的时候直接想出来了,又有点担心复杂度,不过还是打了,居然是直接A掉,开心啊. 我们发现,Ai<=7,这一定是很重要的条件,我们考虑状态压缩,去枚举路径中出现了哪些数字,然后我们把原来n个点拆成 我们枚举数字的最小公倍数 个,因为如果一个数模某个数等于0,那么模它的因数也一定是0,因此我们的思路就是拆点最短路. 1 #include<cstdio> 2 #include<cmath> 3 #include<cstring> 4 #include<al

XJOI网上同步训练DAY3 T2

考试的时候已经想出来怎么做了,但是没有时间打了T_T 思路:我们考虑将询问以lim排序,然后树链剖分,把边作为线段树的节点,然后随着询问lim的增大,改变线段树中节点的信息,然后每次询问我们用树链剖分询问,复杂度是O(nlogn),又get一种新的树链剖分打法 1 #include<cstdio> 2 #include<cmath> 3 #include<iostream> 4 #include<algorithm> 5 #include<cstrin

XJOI夏令营501训练1——分配工作

传送门:QAQQAQ 题意:某公司有工作人员x1,x2,…,xn ,他们去做工作y1,y2,…,ym(n<=m) ,每个人都能做其中的几项工作,并且对每一项工作都有一个固定的效率.问能否找到一种合适的工作分配方案,使得总的效率最高.要求一个人只能参与一项工作,同时一项工作也必须由一个人独立完成.不要求所有的人都有工作. 思路:首先让我们明确二分图匹配算法和网络流的区别:二分图KM算法是网络流最小费用最大流中的特例,即KM算法必须满足每一个x点都被匹配才能运行,但两个算法的前提都是在最大匹配的情况

我理解的朴素贝叶斯模型

我理解的朴素贝叶斯模型 我想说:"任何事件都是条件概率."为什么呢?因为我认为,任何事件的发生都不是完全偶然的,它都会以其他事件的发生为基础.换句话说,条件概率就是在其他事件发生的基础上,某事件发生的概率. 条件概率是朴素贝叶斯模型的基础. 假设,你的xx公司正在面临着用户流失的压力.虽然,你能计算用户整体流失的概率(流失用户数/用户总数).但这个数字并没有多大意义,因为资源是有限的,利用这个数字你只能撒胡椒面似的把钱撒在所有用户上,显然不经济.你非常想根据用户的某种行为,精确地估计一