【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;
}

  

转载于:https://www.cnblogs.com/Delostik/archive/2012/08/15/2640652.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值