【吐槽】
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;
}