【Codeforces #135 Div2】Solutions
English tutorial has been published.You can see here http://codeforces.com/blog/entry/5160
【A k-String】
http://www.codeforces.com/contest/219/problem/A
题目大意:给你一堆字母,问用这些字母能不能组成一个由某个循环节循环k次得到的字符串。
显然我们可以从循环节入手,每个字母出现次数cnt[x]一定是k的整数倍,这样的话每个循环节里就有cnt[x]/k个当前字母。造好循环节之后输出k次就可以了。
#include <iostream> #include <cstring> #include <string> using namespace std; char s[2010],ch; string res; int n,a[50]; int main(){ cin>>n>>s; int len=strlen(s); for(int i=0;i<len;i++){ a[s[i]-'a']++; } if(len<n){ cout<<-1<<endl; return 0; } for(int i=0;i<26;i++){ if(a[i] && a[i]%n!=0){ cout<<-1<<endl; return 0; } } for(int i=0;i<26;i++){ if(a[i]){ for(int j=0;j<(a[i]/n);j++){ ch=i+'a'; res=res+ch; } } } for(int i=1;i<=n;i++) cout<<res; cout<<endl; }
【B Special Offer! Super Price 999 Bourles!】
http://www.codeforces.com/contest/219/problem/B
题目大意:一个数字p,在最多减少d的情况下,p-x末尾数字'9'的个数最多(0≤x≤d)。
这个题的方向是,我们尽量让p的末尾0最多,然后减去一个1,后面的0就都变成9了。
#include <iostream> typedef long long ll; using namespace std; ll p,d,ans; int main(){ cin>>p>>d; ans=++p; for(ll t=10;;t*=10){ if(p%t>d) break; ans=p-p%t; } cout<<ans-1<<endl; }
【C Color Stripe】
http://www.codeforces.com/contest/219/problem/C
题目大意:有n个格子排成一排,有k种颜色,每个格子已经涂了颜色,问多少修改多少个格子的颜色,使得相邻格子颜色不同。
当k=2时,确定第一个格子的颜色,涂色方案就唯一确定,于是可以枚举判断一下。
当k>2时,如果连续一段格子颜色相同,我们显然要对其进行修改。假设区间为[l,r],长度len=r-l+1。当len为奇数时,显然修改{l+1,l+3,l+5...}最优;当长度为偶数时,修改{l,l+2,l+4...}或{l+1,l+3,l+5...}都能保证最优,为了与len为奇数时统一便于coding,我们选后一种修改方法。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int n,k,ans; char s[1000010]; int main(){ cin>>n>>k; cin>>s; if(k==2){ for(int i=0;i<n;i++) if((s[i]-'A')!=i%2) ans++; if(ans>n-ans){ cout<<n-ans<<endl; for(int i=0;i<n;i++) printf("%c",(i+1)%2+'A'); cout<<endl; }else{ cout<<ans<<endl; for(int i=0;i<n;i++) printf("%c",i%2+'A'); cout<<endl; } return 0; } int i=0,last=0; while(i<n){ while(s[i]==s[last]) i++; if(i-last>1){ for(int j=last+1;j<i;j+=2){ for(int k=0;k<3;k++) if(s[j-1]!=k+'A' && s[j+1]!=k+'A'){ ans++; s[j]=k+'A'; break; } } } last=i; } cout<<ans<<endl; cout<<s<<endl; }
【D Choosing Capital for Treeland】
http://www.codeforces.com/contest/219/problem/D
题目大意:一棵有向树,若选取x为“首都”,那么需要将一些边反向使得x到任意点可达。问最少需要将多少边反向,有那些点满足最少的要求。
假定1为根。首先dfs处理出1为“首都”时需要反向的边数。
第二次dfs:假设u是v的父节点,且u的答案已经得到,那么如果v是“首都”,除了从v到u的边需要改变方向之外,从v到v的子节点、从v到u的其他孩子的子节点都是与u为“首都”时相同,所以只需要考虑(u--v)这条边的方向。
#include <iostream> #include <vector> #define inf 2147483647 using namespace std; template<class T>inline void gmin(T &a,T b){if(a>b)a=b;} vector<int> ans_seq; int n,a,b,ans=inf,cnt[200010]; int sum,med,tot; bool vis[200010]; struct EDGE{ int pnt,dist; EDGE *pre; EDGE(){} EDGE(int _pnt,int _dist,EDGE *_pre):dist(_dist),pnt(_pnt),pre(_pre){} }Edge[400010],*SP=Edge,*edge[200010]; inline void addedge(int a,int b){ edge[a]=new(++SP)EDGE(b,0,edge[a]); edge[b]=new(++SP)EDGE(a,1,edge[b]); } void dfs1(int x){ vis[x]=true; for(EDGE *j=edge[x];j;j=j->pre) if(!vis[j->pnt]){ dfs1(j->pnt); cnt[x]+=j->dist+cnt[j->pnt]; } } void dfs2(int x){ vis[x]=false; gmin(ans,cnt[x]); for(EDGE *j=edge[x];j;j=j->pre) if(vis[j->pnt]){ cnt[j->pnt]=j->dist?(cnt[x]-1):(cnt[x]+1); dfs2(j->pnt); } } int main(){ cin>>n; for(int i=1;i<n;i++){ cin>>a>>b; addedge(a,b); } dfs1(1); dfs2(1); for(int i=1;i<=n;i++) if(ans==cnt[i]) ans_seq.push_back(i); cout<<ans<<endl; for(int i=0;i<ans_seq.size()-1;i++) cout<<ans_seq[i]<<" "; cout<<ans_seq[ans_seq.size()-1]<<endl; }
【E Parking Lot】
http://www.codeforces.com/contest/219/problem/E
题目大意:线性排列的一个停车场,依次有车开来或开走。若停车场没有车,那么就安排在1号车位;若已经有车,则要让安排的车位与已经停在这里的车的最小距离最大。输出安排序列。
看到这个题就有思路,可以用线段树维护一个最长的连续全零序列,每次让车停在序列里,有点像“小白逛公园”……结果写了20分钟之后发现越写越恶心,懒标记、每次修改的维护、维护的数据之多(左起、中起、右起最长序列和各自分配的位置……),而且还有左右边界的特判……果断关机睡觉去了……
今天看别人代码发现有用stl维护线段的方法,方便很多。
与线段树一样,维护的是一个空白的连续线段,每个线段有长度(距离)、起点、分配位置三个值,放到set里以长度为关键字排序,从大向小选取即可。
使用map也是可以实现的,也许修改会更方便。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <queue> #include <vector> #include <utility> #include <cmath> #include <string> #include <map> #include <set> #define inf 2147483647 using namespace std; template<class T>inline void gmax(T &a,T b){if(a<b)a=b;} template<class T>inline void gmin(T &a,T b){if(a>b)a=b;} typedef pair<int,int> PII; typedef long long LL; int n,m,sym,id,lot[1000010],L[200010],R[200010]; struct SEGMENT{ int len,st,pos; }cur; struct cmp{ bool operator()(const SEGMENT a,SEGMENT b){ if(a.len==b.len) return a.pos<b.pos; else return a.len>b.len; } }; void match(int x,int y){L[x]=y,R[y]=x;} set<SEGMENT,cmp> seg; SEGMENT Make_seg(int left,int right){ SEGMENT res; if(!left && right==n+1) res.len=inf,res.st=0,res.pos=1; else if(!left) res.len=right-1,res.st=0,res.pos=1; else if(right==n+1) res.len=n-left,res.st=left,res.pos=n; else res.len=(right-left)>>1,res.st=left,res.pos=left+res.len; return res; } void Insert_seg(int left,int right){ L[right]=left,R[left]=right; seg.insert(Make_seg(left,right)); } void Del_seg(int left,int right){ seg.erase(Make_seg(left,right)); } int main(){ cin>>n>>m; Insert_seg(0,n+1); while(m--){ cin>>sym>>id; if(sym==1){ cur=*seg.begin(); seg.erase(seg.begin()); lot[id]=cur.pos; int pnt1=cur.st,pnt2=cur.pos,pnt3=R[pnt1]; Insert_seg(pnt1,pnt2); Insert_seg(pnt2,pnt3); cout<<lot[id]<<endl; }else{ int pnt1=L[lot[id]],pnt2=lot[id],pnt3=R[pnt2]; Del_seg(pnt1,pnt2); Del_seg(pnt2,pnt3); Insert_seg(pnt1,pnt3); } } }
【原创博文,转载请注明出处,谢谢】