Codeforces Round #378 (Div. 2) Analyses
懒癌晚期,没的救了xD
Problems:一只蚂蚱从左跳到右,每次只能跳{A,E,I,O,U,Y},问两次跳之间的距离的最大值
Analysis:简单模拟即可
Tags:Implementation
B.Parade
Problems:给你n排士兵及每排士兵的左、右脚分别伸出的数目,可以交换其中一排的左右脚伸出数,问max{|L-R|}
Analysis:鉴于只有10^5,那么暴力交换就可以了
Tags:Implementation
Problems:给你一个序列和另一个序列,对于后者可以进行merge操作,条件为merge的前者大于后者(R)或后者大于前者(L),问是否可以使后者变成前者,并输出方案
Analysis:首先我们知道后面那个序列要是可能变成前者,那么最后构造出来的数肯定是一一对应的,所以可以从前向后构造,如果不能,则输出否即可,那么考虑构造,对于当前目的序列的x,在原序列若找到一段序列和为x,即视为构造成功,之后方案构造只需向右merge后向左merge再向右merge即可,具体可以看代码实现
Tags:Implementation, Two pointers
#include<cstdio> #include<cstring> #include<algorithm> //#include<iostream> #include<cmath> #include<queue> #include<map> #include<string> #include<vector> using namespace std; #define INF 2000000000 #define Clear(x, Num) memset(x, Num, sizeof(x)) #define Dig(x) ((x>='0') && (x<='9')) #define Neg(x) (x=='-') #define G_c() getchar() #define Maxn 1010 #define Maxe 100010 typedef long long ll; struct Data { int m; char s; }Ans[Maxe]; int n, a[Maxn], b[Maxn], k, Cnt; inline int gcd(int x, int y) { if (!y) return x; return gcd(y, x%y); } inline void read(int &x){ char ch; int N=1; while ((ch=G_c()) && (!Dig(ch)) && (!Neg(ch))); if (Neg(ch)) { N=-1; while ((ch=G_c()) && (!Dig(ch))); } x=ch-48; while ((ch=G_c()) && (Dig(ch))) x=x*10+ch-48; x*=N; } //inline void Insert(int u, int v) { To[Cnt]=v; Next[Cnt]=Head[u]; Head[u]=Cnt++; } inline void Go_die() { puts("NO"); exit(0); } int main() { read(n); for (int i=1; i<=n; i++) read(a[i]); read(k); for (int i=1; i<=k; i++) read(b[i]); int id=1, last=1; for (int i=1; i<=k; i++) { int Max=0, pos=0, _pos=0, Sig=0; for (; (id<=n) && (Sig<b[i]); id++) { Sig+=a[id]; if (Sig>b[i]) Go_die(); if (a[id]>Max) Max=a[id], pos=id; } if (Sig!=b[i]) Go_die(); if ((pos==last) && (a[pos+1]==Max)) while (a[pos+1]==Max) pos++; _pos=pos+1; int Res=i+pos-last; while ((_pos<id) && (a[_pos]<Max)) { Max+=a[_pos++]; Ans[++Cnt].m=Res; Ans[Cnt].s='R'; } int __pos=pos-1; while ((__pos>=last) && (a[__pos]<Max)) { Max+=a[__pos--]; Ans[++Cnt].m=Res--; Ans[Cnt].s='L'; } while ((_pos<id) && (a[_pos]<Max)) { Max+=a[_pos++]; Ans[++Cnt].m=Res; Ans[Cnt].s='R'; } if (Max!=b[i]) Go_die(); last=id; } if (last!=n+1) Go_die(); puts("YES"); for (int i=1; i<=Cnt; i++) printf("%d %c\n", Ans[i].m, Ans[i].s); }
Problems:给你n个长方形,最多选取两个长方形,问能切割出来的最大的球半径的方案
Analysis:这题反倒是比C题好写了,首先对于每个长方形,我们将边长排序,最大半径显然等于最短边的边长,之后考虑合并,合并肯定是有一个面一样然后让另一条边增长为优,所以只需维护面就可以了,需要用到map(或者离散化???)
Tags:Greedy, Data Structure
#include<cstdio> #include<cstring> #include<algorithm> //#include<iostream> #include<cmath> #include<queue> #include<map> #include<string> #include<vector> using namespace std; #define INF 2000000000 #define Clear(x, Num) memset(x, Num, sizeof(x)) #define Dig(x) ((x>='0') && (x<='9')) #define Neg(x) (x=='-') #define G_c() getchar() typedef long long ll; map<pair<int, int> , pair<int, int > > Srh; int n, a, b, c, Min, Mid, Max, Line_max, Merge, Id; inline int gcd(int x, int y) { if (!y) return x; return gcd(y, x%y); } inline void read(int &x){ char ch; int N=1; while ((ch=G_c()) && (!Dig(ch)) && (!Neg(ch))); if (Neg(ch)) { N=-1; while ((ch=G_c()) && (!Dig(ch))); } x=ch-48; while ((ch=G_c()) && (Dig(ch))) x=x*10+ch-48; x*=N; } //inline void Insert(int u, int v) { To[Cnt]=v; Next[Cnt]=Head[u]; Head[u]=Cnt++; } int main() { read(n); for (int i=1; i<=n; i++) { read(a), read(b), read(c); Max=max({a, b, c}), Min=min({a, b, c}), Mid=a+b+c-Max-Min; if (Min>Line_max) Line_max=Min, Id=i, Merge=-1; if (Srh[{Mid, Max}].first) { Min=min({Mid, Max, Min+Srh[{Mid, Max}].first}); if (Min>Line_max) { Line_max=Min; Id=i; Merge=Srh[{Mid, Max}].second; } } Min=min({a, b, c}); Srh[{Min, Mid}]=max(Srh[{Min, Mid}], {Max, i}); Srh[{Min, Max}]=max(Srh[{Min, Max}], {Mid, i}); Srh[{Mid, Max}]=max(Srh[{Mid, Max}], {Min, i}); } if (Merge==-1) { puts("1"); printf("%d\n", Id); } else { puts("2"); printf("%d %d\n", Id, Merge); } }
Codeforces Round #375 (Div. 2) Analyses
神他喵难的一场cf
A.The New Year: Meeting Friends
Problems:三个人要走到一个地方,给定x1,x2,x3,问最小代价。
Analysis:思维题,讨论一下就知道答案为max({x1, x2, x3})-min({x1, x2, x3})
Tags:Math, Sorting
Problems:给定一串字符串,只会出现字母,_以及左右括号,问括号外最长的单词长度以及括号内有几个单词
Analysis:一开始以为括号可以嵌套,感觉巨烦,然而,简单模拟
Tags:Implementation
Problems:题面神他喵的烦,其实就是给定一串序列,让你将其修改,使得1-m数目最小的出现次数最大,且修改次数最小
Analysis:首先出现次数的答案是固定的,即n/m(平均分配)。接下去就是分配的问题了,对于那些>m的数,如果存在一个数小于min(m,n/m),那么就直接修改,否则就不动。之后寻找是否有出现次数<n/m的数,将那些出现次数>n/m的数修改过去就好了
Tags:Greedy
#include<cstdio> #include<cstring> #include<algorithm> //#include<iostream> #include<cmath> #include<queue> #include<map> #include<string> #include<vector> using namespace std; #define INF 2000000000 #define Clear(x, Num) memset(x, Num, sizeof(x)) #define Low(x) ((x>='a') && (x<='z')) #define Cap(x) ((x>='A') && (x<='Z')) #define Dig(x) ((x>='0') && (x<='9')) #define Neg(x) (x=='-') #define G_c() getchar() typedef long long ll; int n, m, a[2010], Cnt[2010], Change; inline int gcd(int x, int y) { if (!y) return x; return gcd(y, x%y); } inline void read(int &x){ char ch; int N=1; while ((ch=G_c()) && (!Dig(ch)) && (!Neg(ch))); if (Neg(ch)) { N=-1; while ((ch=G_c()) && (!Dig(ch))); } x=ch-48; while ((ch=G_c()) && (Dig(ch))) x=x*10+ch-48; x*=N; } //inline void Insert(int u, int v, int w) { To[Cnt]=v; Id[Cnt]=w; Next[Cnt]=Head[u]; Head[u]=Cnt++; } int main() { read(n); read(m); for (int i=1; i<=n; i++) { read(a[i]); if (a[i]<=m) Cnt[a[i]]++; } for (int i=1; i<=m; i++) { int More=(Cnt[i]<(n/m))?(n/m-Cnt[i]):0; if (More) for (int j=1; j<=n; j++) if ((a[j]>m) || (Cnt[a[j]]>n/m)) { if (a[j]<=m) Cnt[a[j]]--; a[j]=i; Change++; More--; if (!More) break; } } printf("%d %d\n", n/m, Change); for (int i=1; i<=n; i++) printf("%d ", a[i]); puts(""); }
Problems:给你一个地图,其中"*"为sand,"."为lake,一个湖的定义为不和边界有交点并被沙子包围,填湖的代价为湖的面积,求湖的个数<=k的最小代价
Analysis:这题反而水了,直接dfs出湖,sort一下贪心就可以了。
Tags:Greedy, Dfs and similar
#include<cstdio> #include<cstring> #include<algorithm> //#include<iostream> #include<cmath> #include<queue> #include<map> #include<string> #include<vector> using namespace std; #define INF 2000000000 #define Clear(x, Num) memset(x, Num, sizeof(x)) #define Low(x) ((x>='a') && (x<='z')) #define Cap(x) ((x>='A') && (x<='Z')) #define Dig(x) ((x>='0') && (x<='9')) #define Neg(x) (x=='-') #define G_c() getchar() typedef long long ll; struct Data { int x, y, Area; }Lake[10010]; int n, m, k, Map[110][110], Ans, Cnt, Ant; bool flag; inline int gcd(int x, int y) { if (!y) return x; return gcd(y, x%y); } inline void read(int &x){ char ch; int N=1; while ((ch=G_c()) && (!Dig(ch)) && (!Neg(ch))); if (Neg(ch)) { N=-1; while ((ch=G_c()) && (!Dig(ch))); } x=ch-48; while ((ch=G_c()) && (Dig(ch))) x=x*10+ch-48; x*=N; } //inline void Insert(int u, int v, int w) { To[Cnt]=v; Id[Cnt]=w; Next[Cnt]=Head[u]; Head[u]=Cnt++; } inline bool Cmp(const Data &a, const Data &b) { return a.Area<b.Area; } inline int dfs(int _x, int _y, int Color) { if ((_x<1) || (_x>n) || (_y<1) || (_y>m) || (Map[_x][_y]==Color) || (!Map[_x][_y])) return 0; if ((_x==1) || (_x==n) || (_y==1) || (_y==m)) { flag=1; return 0; } Map[_x][_y]=Color; return dfs(_x-1, _y, Color)+dfs(_x+1, _y, Color)+dfs(_x, _y-1, Color)+dfs(_x, _y+1, Color)+1; } int main() { scanf("%d%d%d", &n, &m, &k); char x=G_c(); for (int i=1; i<=n; i++) { for (int j=1; j<=m; j++) { x=G_c(); if (x=='.') Map[i][j]=-1; } x=G_c(); } /*for (int i=1; i<=n; i++) { for (int j=1; j<=m; j++) printf("%d ", Map[i][j]); puts(""); }*/ for (int i=1; i<=n; i++) for (int j=1; j<=m; j++) if (Map[i][j]==-1) { flag=0; int Area=dfs(i, j, ++Cnt); if (!flag) Lake[Cnt].x=i, Lake[Cnt].y=j, Lake[Cnt].Area=Area; else Cnt--; } sort(Lake+1, Lake+Cnt+1, Cmp); for (int i=1; i<=Cnt-k; i++) Ans+=Lake[i].Area, dfs(Lake[i].x, Lake[i].y, 0); printf("%d\n", Ans); for (int i=1; i<=n; i++) { for (int j=1; j<=m; j++) if (Map[i][j]) printf("."); else printf("*"); puts(""); } }
Problems:将一个无向图修改,使得入度==出度的点数尽可能的多,并输出方案
Analysis:首先度数为奇的点必然不是答案,那么Res=n-度数为奇的点,再考虑这些点,每次选择从一个点出发进行修改一条路径(直到另一个奇点),经过的点都走偶数次,直到该点度数为0,即可
Tags:Greedy, Dfs and similar, Graphs
#include<cstdio> #include<cstring> #include<algorithm> //#include<iostream> #include<cmath> #include<queue> #include<map> #include<string> #include<vector> using namespace std; #define INF 2000000000 #define Clear(x, Num) memset(x, Num, sizeof(x)) #define Dig(x) ((x>='0') && (x<='9')) #define Neg(x) (x=='-') #define G_c() getchar() typedef long long ll; struct Data { int x, y; }Edge[40010]; int T, n, m, x, y, Edge_Cnt, Res, In[2010]; int G[2010][2010]; inline int gcd(int x, int y) { if (!y) return x; return gcd(y, x%y); } inline void read(int &x){ char ch; int N=1; while ((ch=G_c()) && (!Dig(ch)) && (!Neg(ch))); if (Neg(ch)) { N=-1; while ((ch=G_c()) && (!Dig(ch))); } x=ch-48; while ((ch=G_c()) && (Dig(ch))) x=x*10+ch-48; x*=N; } //inline void Insert(int u, int v) { To[Cnt]=v; Next[Cnt]=Head[u]; Head[u]=Cnt++; } inline void dfs(int u) { while (In[u]) { for (int i=1; i<=n; i++) if (G[u][i]) { int v=i; Edge[++Edge_Cnt].x=u, Edge[Edge_Cnt].y=v; In[u]--, In[v]--; G[u][v]=G[v][u]=0; u=v; break; } } } int main() { read(T); while (T--) { read(n); read(m); Edge_Cnt=0; Res=n; for (int i=1; i<=n; i++) { In[i]=0; for (int j=1; j<=n; j++) G[i][j]=0; } for (int i=1; i<=m; i++) { read(x), read(y); G[x][y]=G[y][x]=1; In[x]++, In[y]++; } for (int i=1; i<=n; i++) Res-=(In[i]&1); printf("%d\n", Res); for (int i=1; i<=n; i++) if (In[i]&1) while (In[i]) dfs(i); for (int i=1; i<=n; i++) while (In[i]) dfs(i); for (int i=1; i<=Edge_Cnt; i++) printf("%d %d\n", Edge[i].x, Edge[i].y); } }
Problems:给你一张图,求一颗生成树,使得源点s度数不超过ds,汇点t度数不超过dt,并按照输入顺序输出
Analysis:先考虑和s,t无关的点集,每个点集只有三种连法
1. 和s和t均相连:标记
2. 和s或者t中的一个相连:直接和另一个点相连。
3. 孤立点:无法构成要求的生成树
对于这些标记点集,若不和s和t联通,则考虑是否可以将s和t相连,若不可以,则无法构成要求的生成树
剩下的点只需要考虑s或者t相连即可
Tags:Greedy, Dsu, Graphs
#include<cstdio> #include<cstring> #include<algorithm> //#include<iostream> #include<cmath> #include<queue> #include<map> #include<string> #include<vector> using namespace std; #define INF 2000000000 #define Clear(x, Num) memset(x, Num, sizeof(x)) #define Dig(x) ((x>='0') && (x<='9')) #define Neg(x) (x=='-') #define G_c() getchar() #define Maxn 200010 #define Maxe 800010 typedef long long ll; vector<int >Point[Maxn]; int n, m, x[Maxe], y[Maxe], To[Maxe], Next[Maxe], Id[Maxe], Head[Maxn], Cnt; int source, sink, dep_s, dep_t; int f[Maxn], Ans_s[Maxn], Ans_t[Maxn], Cnt_s, Cnt_t; bool Used[Maxe]; inline int Get_f(int x) { return (x==f[x])?(x):(f[x]=Get_f(f[x])); } inline int gcd(int x, int y) { if (!y) return x; return gcd(y, x%y); } inline void read(int &x){ char ch; int N=1; while ((ch=G_c()) && (!Dig(ch)) && (!Neg(ch))); if (Neg(ch)) { N=-1; while ((ch=G_c()) && (!Dig(ch))); } x=ch-48; while ((ch=G_c()) && (Dig(ch))) x=x*10+ch-48; x*=N; } inline void Insert(int u, int v, int w) { To[Cnt]=v; Id[Cnt]=w; Next[Cnt]=Head[u]; Head[u]=Cnt++; } int main() { read(n); read(m); for (int i=1; i<=n; i++) Head[i]=-1; Cnt=0; for (int i=1; i<=m; i++) { read(x[i]); read(y[i]); Insert(x[i], y[i], i), Insert(y[i], x[i], i); } read(source); read(sink); read(dep_s); read(dep_t); for (int i=1; i<=n; i++) f[i]=i; for (int u=1; u<=n; u++) if ((u^source) && (u^sink)) for (int p=Head[u]; p!=-1; p=Next[p]) { int v=To[p]; if ((v==source) || (v==sink)) continue; int Anc_u=Get_f(u), Anc_v=Get_f(v); if (Anc_u^Anc_v) Used[Id[p]]=1, f[Anc_u]=Anc_v; } for (int i=1; i<=n; i++) Point[Get_f(i)].push_back(i); for (int u=1; u<=n; u++) if ((u^source) && (u^sink) && (f[u]==u)) { int Link_source=0, Link_sink=0; for (int p=0; p<Point[f[u]].size(); p++) { int v=Point[u][p]; if (f[v]==u) { for (int _p=Head[v]; _p!=-1; _p=Next[_p]) { int _v=To[_p]; if (_v==source) Link_source=Id[_p]; else if (_v==sink) Link_sink=Id[_p]; } if ((Link_source) && (Link_sink)) break; } } if ((!Link_source) && (!Link_sink)) { puts("No"); return 0; } if ((Link_source) && (Link_sink)) Ans_s[++Cnt_s]=Link_source, Ans_t[++Cnt_t]=Link_sink; else { if (Link_source) dep_s--, f[u]=source, Used[Link_source]=1; if (Link_sink) dep_t--, f[u]=sink, Used[Link_sink]=1; } } if (Cnt_s) dep_s--, dep_t--, Used[Ans_s[1]]=1, Used[Ans_t[1]]=1; else { int Anc=Get_f(1); for (int i=1; i<=n; i++) if (Get_f(i)^Anc) { Anc=-1; break; } if (Anc==-1) { bool flag=0; for (int p=Head[source]; p!=-1; p=Next[p]) { int v=To[p]; if (v==sink) { flag=1; Used[Id[p]]=1; break; } } if (!flag) { puts("No"); return 0; } dep_s--; dep_t--; f[source]=sink; } } for (int i=2; i<=Cnt_s; i++) { if (dep_s) { dep_s--, Used[Ans_s[i]]=1; continue; } dep_t--, Used[Ans_t[i]]=1; } if ((dep_s<0) || (dep_t<0)) { puts("No"); return 0; } puts("Yes"); for (int i=1; i<=m; i++) if (Used[i]) printf("%d %d\n", x[i], y[i]); }
Codeforces Round #377 (Div. 2) Analyses
拖了两天、不能再懒更多了
Problem:你有∞多的10和一个r∈[0, 9]以及一个物品的价格k,问你买多少该物品可以恰好不用找钱
Analysis:不用找钱 <=> 10的倍数或者10的倍数+r,模拟即可
Tags:Implementation
B.Cormen --- The Best Friend Of a Man
Problem:给定一串长度为n的序列,要求相邻两项之和不得小于k,支持修改,问最小代价
Analysis:贪心显然成立(改变第二天对后继的更优),所以模拟修改的过程即可。然而坑点在于n == 1的情况,是不用特判的
Tags:Greedy
Problem:有个人在医院里不知道呆了几天,只知道自己吃的早饭,中饭,晚饭数量,问你他最少没吃多少餐
Analysis:知道最小天数就可以反向推出他最少没吃多少餐了,而前者显然是max{ breakfast, dinner, supper }-1;
Tags:Math, Greedy
D.Exams
Problem:n天内需要考m门试题,每天可以选择考试(当天只能考当天提供的考试),复习,或者什么都不做、求最小需要的天数
Analysis:二分显然,重点在于如何判断。注意到最后一天其实只能考试了,然后逆推统计复习天数判断是否可行就可以了
Tags:Binary search, Greedy
#include<cstdio> #include<cstring> #include<algorithm> //#include<iostream> #include<cmath> #include<queue> #include<map> #include<string> #include<vector> using namespace std; #define INF 2000000000 #define Clear(x, Num) memset(x, Num, sizeof(x)) #define Dig(x) ((x>='0') && (x<='9')) #define Neg(x) (x=='-') #define G_c() getchar() #define Maxn 100010 typedef long long ll; int n, m, d[Maxn], a[Maxn]; bool Pass[Maxn]; inline int gcd(int x, int y) { if (!y) return x; return gcd(y, x%y); } inline void read(int &x){ char ch; int N=1; while ((ch=G_c()) && (!Dig(ch)) && (!Neg(ch))); if (Neg(ch)) { N=-1; while ((ch=G_c()) && (!Dig(ch))); } x=ch-48; while ((ch=G_c()) && (Dig(ch))) x=x*10+ch-48; x*=N; } //inline void Insert(int u, int v) { To[Cnt]=v; Next[Cnt]=Head[u]; Head[u]=Cnt++; } inline bool Judge(int Day) { Clear(Pass, 0); int Cnt=0; for (int i=Day; i>=1; i--) if ((d[i]) && (!Pass[d[i]])) Pass[d[i]]=1, Cnt+=a[d[i]]; else Cnt--, Cnt=max(Cnt, 0); if (Cnt) return 0; for (int i=1; i<=m; i++) if (!Pass[i]) return 0; return 1; } int main() { read(n); read(m); for (int i=1; i<=n; i++) read(d[i]); for (int i=1; i<=m; i++) read(a[i]); int l=1, r=n; while (l<=r) { int mid=(l+r)>>1; if (Judge(mid)) r=mid-1; else l=mid+1; } if (Judge(l)) printf("%d\n", l); else puts("-1"); }
E.Sockets
Problem:有n个电脑需要供电,你有m个电源,和∞多个适配器,每个适配器可以使某个电源电压减半,供电必要的条件为电脑的电压<=电源电压,问最大所连接的电脑数和最小需要的适配器的数量
Analysis:贪心,将电源排序,如果一个小的电源匹配不了的话,那么用更大的加适配器就是浪费,所以从电源电压小的开始匹配,由于数据范围,需要用map来保存。(还有一种优先队列的模拟方法)
Tags:Greedy, Sorting, Implementation
#include<cstdio> #include<cstring> #include<algorithm> //#include<iostream> #include<cmath> #include<queue> #include<map> #include<string> #include<vector> using namespace std; #define INF 2000000000 #define Clear(x, Num) memset(x, Num, sizeof(x)) #define Dig(x) ((x>='0') && (x<='9')) #define Neg(x) (x=='-') #define G_c() getchar() #define Maxn 200010 typedef long long ll; struct Socket { int s, id; }s[Maxn]; int n, m, x, Apt, Match; int Link[Maxn], Ans[Maxn]; map<int, vector<int > > Com; inline int gcd(int x, int y) { if (!y) return x; return gcd(y, x%y); } inline void read(int &x){ char ch; int N=1; while ((ch=G_c()) && (!Dig(ch)) && (!Neg(ch))); if (Neg(ch)) { N=-1; while ((ch=G_c()) && (!Dig(ch))); } x=ch-48; while ((ch=G_c()) && (Dig(ch))) x=x*10+ch-48; x*=N; } //inline void Insert(int u, int v) { To[Cnt]=v; Next[Cnt]=Head[u]; Head[u]=Cnt++; } inline bool cmp(const Socket &a, const Socket &b) { return (a.s<b.s) || ((a.s==b.s) && (a.id<b.id)); } int main() { read(n); read(m); for (int i=1; i<=n; i++) read(x), Com[x].push_back(i); for (int i=1; i<=m; i++) read(s[i].s), s[i].id=i; sort(s+1, s+m+1, cmp); for (int i=1; i<=m; i++) { int Current=s[i].s, Cnt=0; while (1) { if (Com[Current].size()!=0) { int Cp=Com[Current][Com[Current].size()-1]; Com[Current].pop_back(); Match++, Apt+=Cnt; Link[Cp]=s[i].id, Ans[s[i].id]=Cnt; break; } if (Current==1) break; Cnt++, Current=(Current+1)>>1; } } printf("%d %d\n", Match, Apt); for (int i=1; i<=m; i++) printf("%d ", Ans[i]); puts(""); for (int i=1; i<=n; i++) printf("%d ", Link[i]); puts(""); }
Problem:给你一个无向无环图,让你确定每条边的方向,使得所有点能到达的点的个数种最小值的最大值
Analysis:首先想到二分+缩点,但手推几个图后发现其实答案就是max{ V’ },V’为某个强连通块中的点的个数,那么两遍Tarjan即可,第一遍寻找该节点,第二遍模拟建图
Tags:Dfs and similar, Algorithm
#include<cstdio> #include<cstring> #include<algorithm> //#include<iostream> #include<cmath> #include<queue> #include<map> #include<string> #include<vector> using namespace std; #define INF 2000000000 #define Clear(x, Num) memset(x, Num, sizeof(x)) #define Dig(x) ((x>='0') && (x<='9')) #define Neg(x) (x=='-') #define G_c() getchar() #define Maxn 400010 #define Maxe 800010 typedef long long ll; struct Answer { int u, v; }Link[Maxe]; int n, m, x, y, Res, Cnv, Index, dfn[Maxn], low[Maxn], Stack[Maxe], Point; int To[Maxe], Id[Maxe], Head[Maxn], Cnt, Next[Maxe]; inline int gcd(int x, int y) { if (!y) return x; return gcd(y, x%y); } inline void read(int &x){ char ch; int N=1; while ((ch=G_c()) && (!Dig(ch)) && (!Neg(ch))); if (Neg(ch)) { N=-1; while ((ch=G_c()) && (!Dig(ch))); } x=ch-48; while ((ch=G_c()) && (Dig(ch))) x=x*10+ch-48; x*=N; } inline void Insert(int u, int v, int w) { To[Cnt]=v; Id[Cnt]=w; Next[Cnt]=Head[u]; Head[u]=Cnt++; } inline void Init_Tarjan() { for (int i=1; i<=n; i++) dfn[i]=0; Cnv=Index=Res=0; } inline void Tarjan(int u, int father) { dfn[u]=low[u]=++Index; Stack[++Cnv]=u; for (int p=Head[u]; p!=-1; p=Next[p]) { int v=To[p], pos=Id[p]; if (v==father) continue; if (!dfn[v]) { Link[pos].u=v, Link[pos].v=u; Tarjan(v, u); low[u]=min(low[u], low[v]); } else Link[pos].u=u, Link[pos].v=v, low[u]=min(low[u], dfn[v]); } if (dfn[u]==low[u]) { int Tmp, Count=0; do { Tmp=Stack[Cnv--]; Count++; }while (Tmp!=u); if (Res<Count) Res=Count, Point=u; } } /*inline bool Judge(int Current) { for (int i=1; i<=n; i++) dfn[i]=0; Cnv=Index=Res=0; Tarjan(1, -1); return (Res>=Current); }*/ int main() { read(n); read(m); Clear(Head, -1); Cnt=0; for (int i=1; i<=m; i++) read(x), read(y), Insert(x, y, i), Insert(y, x, i); /*int l=1, r=n; while (l<=r) { int mid=(l+r)>>1; if (Judge(mid)) l=mid+1; else r=mid-1; }*/ Init_Tarjan(); Tarjan(1, -1); printf("%d\n", Res); Init_Tarjan(); Tarjan(Point, -1); for (int i=1; i<=m; i++) printf("%d %d\n", Link[i].u, Link[i].v); }