• 【Codeforces #133 Div2】Solutions


    【吐槽】

      1.发烧打吊瓶,晚上坚持不住睡着了,没赶上比赛……

      2.CF的官方英文题解出的真是够慢的……

      3.cin cout什么的能用就用了管他慢不慢……我就懒死……

    ==============================================================================================

    【A  Tiling with Hexagons】

      http://codeforces.ru/contest/216/problem/A

      题目大意:对边平行且相等的大六边形里面排列若干小六边形,大六边形的边长n表示在这条边的方向上排列着n个小六边形。看图吧= =

                                                                       a=2 , b=3 , c=4

      初看这个题没什么思路,也不好讲……但是在Comment里面看到一个很不错的图片,解法一目了然。

                          

      答案为a*b+b*c+a*c-a-b-c+1

    #include <iostream>
    using namespace std;
    int a,c,b;
    int main(){
    	cin>>a>>b>>c;
    	cout<<a*b+a*c+b*c-a-b-c+1<<endl;
    }
    

      

    【B  Forming Teams】

      http://codeforces.ru/contest/216/problem/B

      题目大意:足球赛要分成两组,有些人之间有仇恨关系不能分在一组,且仇恨关系有传递相互性。当无法完成分组时,就要让一部分人坐在替补席上不上场。问最少让几个人不上场。

      构图之后,会出现环、链、联通块什么的。发现不能分组的情况只出现在奇环,如果出现奇环,那就要让一个人下去坐着。并查集维护即可。

      注意的地方:1.题目有关于点的度数最大为2的提示,比较隐蔽。

                2.处理完所有奇环之后还要看剩下的人数能不能平均分开。

    #include <iostream>
    using namespace std;
    
    int fa[110],size[110],ans,n,m;
    
    int find(int x){
    	if(x==fa[x]) return x;
    	else return fa[x]=find(fa[x]);
    }
    
    int main(){
    	cin>>n>>m;
    	for(int i=1;i<=n;i++) 
    		fa[i]=i,size[i]=1;
    	while(m--){
    		int x,y;
    		cin>>x>>y;
    		int fx=find(x),fy=find(y);
    		if(fx==fy && (size[fx]&1)) ans++;
    		fa[fy]=fx,size[fx]+=size[fy];
    	}
    	if((n-ans)&1) ans++;
    	cout<<ans<<endl;
    }
    

      

    【C  Hiring Staff】

      http://codeforces.ru/contest/216/problem/c

      题目大意:老板要雇服务员,服务员工作n天,休息m天,如此往复。店只有一把钥匙,拿钥匙的员工如果第二天休息,就要在工作最后一天把钥匙传给别人……还得保证每天店里至少k个服务员,问最少雇多少,什么时间雇。

      这道题显然满足贪心的性质,提前雇员工没有意义,摆在那也不能使决策更优,所以在需要的时候雇员工即可。雇员工的条件有两个:1.员工不够;2.没有员工明天来开门。

    #include <iostream>
    #include <vector>
    using namespace std;
    
    vector<int> ans;
    int n,m,k,E[2020],delta;
    
    int main(){
    	cin>>n>>m>>k;
    	for(int i=1;i<=n+m;i++){
    		delta=0;
    		if(E[i]<k) delta=k-E[i];
    		if(!E[i+1] && !delta) delta=1;
    		if(delta){
    			for(int j=i;j<i+n;j++)
    				E[j]+=delta;
    			while(delta--) ans.push_back(i);
    		}
    	}
    	cout<<ans.size()<<endl;
    	for(int i=0;i<ans.size();i++)
    		cout<<ans[i]<<" ";
    }
    

      

    【D  Spider's Web】

      http://codeforces.ru/contest/216/problem/D

      题目大意:某蜘蛛结了如下的网……每个小块左右两边(姑且这么叫吧)的交点数量相等,这个块就被成为stable(greed area),否则就是unstable(red area)。问unstable的数量。

      题挺水的,枚举每一个块,用他的内径外径作为限制,在相邻两边统计焦点数目。

      如何统计?二分答案,找到上下边界,中间的元素个数就出来了。

      C++党使用STL瞬间减少若干行。。。

    #include <iostream>
    #include <algorithm>
    #include <vector>
    using namespace std;
    
    vector<int> dist[1000];
    int n,m,x,ans;
    
    int main(){
    	cin>>n;
    	for(int i=0;i<n;i++){
    		cin>>m;
    		while(m--){
    			cin>>x;
    			dist[i].push_back(x);
    		}
    		sort(dist[i].begin(),dist[i].end());
    	}
    	for(int i=0;i<n;i++){
    		int last=(i+n-1)%n,next=(i+1)%n;
    		for(int j=1;j<dist[i].size();j++){
    			int low=dist[i][j-1],high=dist[i][j];
    			int P_last=upper_bound(dist[last].begin(),dist[last].end(),high)-lower_bound(dist[last].begin(),dist[last].end(),low);
    			int P_next=upper_bound(dist[next].begin(),dist[next].end(),high)-lower_bound(dist[next].begin(),dist[next].end(),low);
    			ans+=(P_last!=P_next);
    		}
    	}
    	cout<<ans<<endl;
    }
    

      

    【E  Martian Luck】【UPD2】

      http://codeforces.ru/contest/216/problem/E

      题目大意:一个数字的数字根定义为在k进制下各位数字相加,重复若干次,得到的一位数。如果一个数字的数字根为b,那么这个数字就很lucky。给你一个数字串,问有多少个连续字串组成的数字是lucky的。

      首先必须了解数字根。数字根有以下性质(跟这个题相关的):

      1.一个数x加9的数字根是x的数字根。比如:8+9=17,R(17)=8;12+9=21,R(21)=R(12).

      2.一个数x乘9的数字根是9.比如:6*9=54,R(54)=9.

      3.若A+B=C,则R(a)+R(b)=R(c).

        证明:由性质(1)(2)可将每个数字分解为若干9与其数字根的和,A=9n+R(A) , B=9m+R(B) , C=9p+R(C) .

             则R(A)+R(B)=R(C)+9(p-m-n) .再由性质(1)(2)知9的倍数对数字根没有影响,得证。


      由性质3,我们在这道题求解字串数字根的事时候就可以用前缀和维护。

      由于题目允许前导0,所以在统计的时候还需要统计0对答案的影响。

      当b=0时,答案就是选取0的方案数;b=k-1时,由于取模运算会出现0,所以要防止0被重复计算。

      顺次统计每一位,f(sum)=(sum-b) mod (k-1),我用了一个map记录数字根出现的次数方便查找。

    #include <iostream>
    #include <map>
    using namespace std;
    map<int,int> m;
    long long ans,sum;
    int k,b,n,x,cnt;
    int main(){
    	cin>>k>>b>>n;
    	if(!b){
    		for(int i=0;i<n;i++){
    			cin>>x;
    			cnt=x?0:(cnt+1);
    			ans+=cnt;
    		}
    	}else{
    		k--,m[0]=1;
    		for(int i=0;i<n;i++){
    			cin>>x;
    			sum+=x;
    			cnt=x?0:(cnt+1);
    			ans+=m[(sum-b+k)%k];
    			m[sum%=k]++;
    			if(b==k) ans-=cnt;
    		}
    	}
    	cout<<ans<<endl;
    }
    

      

  • 相关阅读:
    【洛谷P3628】特别行动队
    【洛谷P3233】世界树
    【BZOJ1597】土地购买
    【洛谷P4068】数字配对
    【洛谷P3899】谈笑风生
    【BZOJ2726】任务安排
    【洛谷P6186】[NOI Online 提高组] 冒泡排序
    【洛谷P3369】【模板】普通平衡树
    【UOJ#8】Quine
    标准 插入flash
  • 原文地址:https://www.cnblogs.com/Delostik/p/2640652.html
Copyright © 2020-2023  润新知