zoukankan      html  css  js  c++  java
  • 【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);
    		}
    	}
    }
    

      

    【原创博文,转载请注明出处,谢谢】

  • 相关阅读:
    Rust 包管理器 Cargo 入门
    如何设置对企业批量的图文档加密?2021企业首选公司文档加密方案,宁波风奥金甲数据防泄漏
    跟坚哥学QUIC系列:加密和传输握手
    如何在SQLServer中处理每天四亿三千万记录的
    高德最佳实践:Serverless 规模化落地有哪些价值?
    浅谈 Pull Request 与 Change Request 研发协作模式
    Dbeaver连接国产数据库人大金仓
    我对云原生软件架构的观察与思考
    Java Web整合开发(20) -- Hibernate入门
    2 修改与恢复
  • 原文地址:https://www.cnblogs.com/Delostik/p/2660073.html
Copyright © 2011-2022 走看看