Educational Codeforces Round 2
600A - Extract Numbers 20171106
字符串处理题,稍微注意点细节就能水过
#include<stdlib.h> #include<stdio.h> #include<math.h> #include<vector> #include<cstring> #include<iostream> #include<algorithm> using namespace std; string s;int _; vector<string>a,b; void check(int l,int r) { if(l==r){b.push_back("");return;} if(l==r-1) { if(s[l]>='0' && s[l]<='9') a.push_back(""),a[a.size()-1].assign(s,l,r-l); else b.push_back(""),b[b.size()-1].assign(s,l,r-l); return; } if(s[l]=='0'){b.push_back(""),b[b.size()-1].assign(s,l,r-l);return;} for(int i=l;i<r;i++) if(s[i]<'0' || s[i]>'9') { b.push_back(""); b[b.size()-1].assign(s,l,r-l); return; } a.push_back(""); a[a.size()-1].assign(s,l,r-l); } int main() { cin>>s; for(int i=0;i<s.size();i++) if(s[i]==',' || s[i]==';') check(_,i),_=i+1;check(_,s.size()); if(a.size()==0)printf("-\n");else{cout<<char(34); for(int i=0;i<a.size();i++) {cout<<a[i];printf("%c",i==a.size()-1?'"':',');}cout<<endl;} if(b.size()==0)printf("-\n");else{cout<<char(34); for(int i=0;i<b.size();i++) {cout<<b[i];printf("%c",i==b.size()-1?'"':',');}cout<<endl;} return 0; }
600B - Queries about less or equal elements 20171106
对a数组排序后upperbound一下就好了,当然想手写二分也不拦着╮(╯▽╰)╭
#include<stdlib.h> #include<stdio.h> #include<math.h> #include<vector> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int n,m,x; int a[200001]; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); sort(a+1,a+n+1); for(int i=1;i<=m;i++) {scanf("%d",&x);cout<<upper_bound(a+1,a+n+1,x)-a-1<<endl;} return 0; }
600C - Make Palindrome 20171106
由于可以改变排列顺序,所以尽可能地把大的出现次数为奇数的字母改为小的出现次数为奇数的字母一定是最优的
#include<stdlib.h> #include<stdio.h> #include<math.h> #include<vector> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int pos[26],sum[26],l,r; string s; int main() { cin>>s; for(int i=0;i<s.size();i++) pos[s[i]-'a']=i,sum[s[i]-'a']++; int mid=-1;l=0,r=25; while(l<r) { while(sum[l]%2==0 && l<26)l++; while(sum[r]%2==0 && r>=0)r--; if(l>=r)break; s[pos[r]]=l+'a'; sum[l++]++,sum[r--]--; } for(int i=0;i<26;i++) if(sum[i]&1)mid=i; sort(s.begin(),s.end()); for(int i=0;i<s.size();i+=2) { if(s[i]==mid+'a' && i%2==0)i++; if(i<s.size())cout<<s[i]; } if(mid!=-1)cout<<char(mid+'a'); for(int i=s.size()-1;i>=0;i-=2) { if(s[i]==mid+'a')i--,mid=-1; if(i>=0)cout<<s[i]; } cout<<endl;return 0; }
600D - Area of Two Circles' Intersection 20171111 20180831
一道计算几何模板题,当年没有模板的时候被卡精度卡成SB,结果发现把输出小数位数减少到6位就过了...前两天测试学长模板的时候直接秒掉了【论模板的重要性】
附上当年蠢得一比的代码
#include<stdlib.h> #include<stdio.h> #include<math.h> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const long double pi=acos(-1.0); struct Circle{long double x,y,r;}c1,c2; double ans; void print(){printf("%.6lf\n",ans);} int main() { cin>>c1.x>>c1.y>>c1.r>>c2.x>>c2.y>>c2.r; long double dis=pow(pow(c1.x-c2.x,2)+pow(c1.y-c2.y,2),0.5); if(c1.r+c2.r<=dis)return ans=0,print(),0; if(c1.r-c2.r>=dis)return ans=pi*c2.r*c2.r,print(),0; if(c2.r-c1.r>=dis)return ans=pi*c1.r*c1.r,print(),0; long double angle1=2*acos((c1.r*c1.r+dis*dis-c2.r*c2.r)/(2*dis*c1.r)); long double angle2=2*acos((c2.r*c2.r+dis*dis-c1.r*c1.r)/(2*dis*c2.r)); long double s1=c1.r*c1.r*angle1/2,s2=c2.r*c2.r*angle2/2; long double t1=sin(angle1)*c1.r*c1.r/2,t2=sin(angle2)*c2.r*c2.r/2; ans=s1-t1+s2-t2,print(); return 0; }
600E - Lomsat gelral 20180902
启发式合并,和Codeforces 375D的做法类似,直接套用了之前的代码魔改一下就过了_(:з」∠)_
#include<bits/stdc++.h> using namespace std; #define N 100001 #define LL long long LL ans[N]; int n,x,y,c[N]; vector<int>d[N]; map<int,LL>cnt[N],f[N]; void dfs(int cur,int pre) { cnt[cur][c[cur]]=1,f[cur][1]=c[cur]; for(auto nxt:d[cur])if(nxt!=pre) { dfs(nxt,cur); if(cnt[nxt].size()>cnt[cur].size()) cnt[cur].swap(cnt[nxt]),f[cur].swap(f[nxt]); for(auto x:cnt[nxt]) { int y=cnt[cur][x.first]; cnt[cur][x.first]+=x.second; for(int i=y+1;i<=y+x.second;i++) f[cur][i]+=x.first; } } ans[cur]=(*f[cur].rbegin()).second; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&c[i]); for(int i=2;i<=n;i++) scanf("%d%d",&x,&y), d[x].push_back(y), d[y].push_back(x); dfs(1,0); for(LL i=1;i<=n;i++) printf("%I64d%c",ans[i],i<n?' ':'\n'); return 0; }
600F - Edge coloring of bipartite graph 20180902
显然颜色种数是各顶点度数的最大值,下面给出一种构造方法
每次读入一条边时,分别查找该边的两顶点 u,v 的第一个未被用过的颜色,设其为c1,c2 。若c1==c2,则直接染色,否则由于v这边c1已经被占用,我们需要查找到与v共享颜色c1的点w,并将v与w之间的边改为颜色c2,这样u与v之间就可以连上一条颜色为c1的边了。在改边[v,w]的颜色时,也可能会出现w这边c2已经被占用的情况,这时就需要递归进行操作(类似于匈牙利算法的做法)。显然这样做的复杂度最大是O(n),那么整个程序的时间复杂度就是O(mn)
#include<bits/stdc++.h> using namespace std; #define N 2001 #define M 100001 struct rua{int v,id;}; int a,b,m,u,v,ans,x[N][N],f[N][N],c[M]; void dfs(int u,int v,int c1,int c2) { int w=x[v][c1]; x[v][c1]=u,x[u][c1]=v; if(w)dfs(v,w,c2,c1); else x[v][c2]=0; } int main() { scanf("%d%d%d",&a,&b,&m); for(int i=1;i<=m;i++) { scanf("%d%d",&u,&v),v+=a; f[u][v]=f[v][u]=i; int c1=1,c2=1; while(x[u][c1])c1++; while(x[v][c2])c2++; if(c1==c2)x[u][c1]=v,x[v][c2]=u; else dfs(u,v,c1,c2); ans=max(ans,max(c1,c2)); } for(int i=1;i<=a;i++) for(int j=1;j<=ans;j++) if(x[i][j])c[f[i][x[i][j]]]=j; printf("%d\n",ans); for(int i=1;i<=m;i++) printf("%d%c",c[i],i<m?' ':'\n'); return 0; }