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);
}
}
}
【原创博文,转载请注明出处,谢谢】