Contest:http://codeforces.com/contest/1133
这场比赛差2分钟。就交上F了。。结果没交上,又掉分了,掉分一时惨,一直掉分一直惨
A. Middle of the Contest(签到)
题目链接:http://codeforces.com/contest/1133/problem/A
题目大意:给你两个时间,让你输出两个时间的中点时间。
思路:题目保证数据在同一天&&时间间隔为偶数,那么直接得出总时间,然后/2,再输出start+一般时间即可。
ACCode:
int main(){
int h1,m1,h2,m2;
while(~scanf("%d:%d",&h1,&m1)){
scanf("%d:%d",&h2,&m2);
int res=(h2-h1)*60+m2-m1;
res/=2;res+=m1;
int ansh=h1+res/60,ansm=res%60;
printf("%02d:%02d\n",ansh,ansm);
}
}
B. Preparation for International Women's Day(思维+暴力)
题目链接:http://codeforces.com/contest/1133/problem/B
题目大意:n个数据,从中两两选择一对,使(a[i]+a[j])%k==0,看有多少对。
思路:所有数对k取模,因为k比较小,然后遍历k。从中选取整数个区间。最后输出答案就好了。(此处@猛哥,这个算法还是他想出来的,当时我想了好久都没想出来解决办法)
ACCode:
const int MAXN=1e5+10;
const ll INF=1e16;
const ll mod=1e9+7;
int res[110];
int main(){
int n,k,e;scanf("%d%d",&n,&k);
for(int i=1;i<=n;++i){
scanf("%d",&e);e=e%k;res[e]++;
}int ans=0;
for(int i=1;i<k;++i){
if(i==k-i) ans+=(res[i]/2)*2;
else ans+=min(res[i],res[k-i]);
}ans+=(res[0]/2)*2;
cout<<ans<<endl;
}
C. Balanced Team(尺取)
题目链接:http://codeforces.com/contest/1133/problem/C
题目大意:n个数据,从中选出maxa[i]-mina[i]<=5的一组。问最多选多少个数。
思路:sort之后尺取。
ACCode:
const int MAXN=2e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const int MOD=1e9+7;
const double EPS=1.0e-8;
int a[MAXN];
int main(){
int n;
while(cin>>n){
for(int i=1;i<=n;++i){
cin>>a[i];
}sort(a+1,a+1+n);
int ans=0,res=0,start=1,end=1;
for(int i=1;i<=n;++i){
if(a[i]-a[start]<=5){
res++;ans=max(ans,res);
}
else{
while(a[i]-a[start]>5) start++;
res=i-start+1;ans=max(ans,res);
}
}cout<<ans<<endl;
}
}
D. Zero Quantity Maximization(思维+暴力)
题目链接:http://codeforces.com/contest/1133/problem/D
题目大意:有两个n个元素的数组a,b。每个找出一个d使得一个新数组c满足c[i]=d*a[i]+b[i];为使数组c中的0的个数最多,问最大的d是多少。
思路:满足c[i]=d*a[i]+b[i],要使c[i]变成0,那么就是d=a[i]/b[i],我们把a[i]/b[i]化简之后存起来,然后找出现最多的a[i]/b[i]就行了。再加上其他的边界特判。
ACCode:
#define ll long long
#define Pair pair<ll,ll>
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// ??
//std::ios::sync_with_stdio(false);
// register
const int MAXN=2e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll mod=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
ll a[MAXN],b[MAXN];
map<Pair,int> mp;
ll GCD(ll a,ll b){
if(b==0) return a;
return GCD(b,a%b);
}
int main(){
int n;
while(~scanf("%d",&n)){
for(int i=1;i<=n;++i){
scanf("%lld",&a[i]);
}
for(int i=1;i<=n;++i){
scanf("%lld",&b[i]);
}int ans=0,add=0,ex=0;
for(int i=1;i<=n;++i){
if(a[i]==0&&b[i]==0){
ex++;continue;
}
if(b[i]==0){//a[i]*0;
add++;continue;
}
if(a[i]==0) continue;
ll Gcd=GCD(a[i],b[i]);//cout<<Gcd<<endl;
while(abs(Gcd)>1){
a[i]/=Gcd;b[i]/=Gcd;
Gcd=GCD(a[i],b[i]);
}Pair temp;
if(a[i]*b[i]<0) temp=make_pair(abs(a[i]),abs(b[i]));
else temp=make_pair(abs(a[i]),-abs(b[i]));
// cout<<temp.first<<" "<<temp.second<<endl;
mp[temp]++;//cout<<res<<endl;
ans=max(ans,mp[temp]);
}printf("%d\n",max(add+ex,ans+ex));
}
}
E. K Balanced Teams(简单DP)
题目链接:http://codeforces.com/contest/1133/problem/E
题目大意:给出n个元素的数组,从中选出k个队伍。满足每个队伍中的两两元素之间的差值<=5.问能选出多少个人。
思路:很明显的简单DP,按元素大小排序,然后对于每个小组,都选择所能选择的最大的人数。
状态转移方程:DP[i][j]=max(DP[i][j-1],DP[i-1][(a[j]-6)元素出现的位置]+j-(a[j]-6)元素出现的位置)。
DP[i][j]的意思就是前j个人中组成i个小组的最大人数。
ACCode:
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define Pair pair<int,int>
#define M_P(a,b) make_pair(a,b)
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// ??
//std::ios::sync_with_stdio(false);
// register
const int MAXN=5e3+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
int DP[MAXN][MAXN];
int a[MAXN];
int n,k;
int get_x(int key){
int l=1,r=n,mid;
while(l<=r){
mid=(l+r)>>1;
if(a[mid]>key) r=mid-1;
else l=mid+1;
}return r;
}
int main(){
while(~scanf("%d%d",&n,&k)){
clean(DP,0);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
sort(a+1,a+1+n);
for(int i=1;i<=k;++i){
for(int j=1;j<=n;++j){
int front=get_x(a[j]-6);
DP[i][j]=max(DP[i][j-1],DP[i-1][front]+(j-front));
}
}printf("%d\n",DP[k][n]);
}
}
F1. Spanning Tree with Maximum Degree(简单搜索)
题目链接:http://codeforces.com/contest/1133/problem/F1
题目大意:给你一个n个节点,m条边的图,找出其中的一个生成树,这个生成树要满足其中的每个节点的度是最大的。
思路:找到度数最大的节点,然后从那个节点开始向下BFS,遇到的点就输出。
ACCode:
// luogu-judger-enable-o2
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define Pair pair<int,int>
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// ˮӡ
//std::ios::sync_with_stdio(false);
// register
const int MAXN=2e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const int MOD=1e9+7;
const double EPS=1.0e-8;
struct node{
int v,nxt,val;
node(int _v=0,int _val=0,int _nxt=0){
v=_v;val=_val;nxt=_nxt;
}
}edge[MAXN<<2];
int head[MAXN],ecnt;
int Vis[MAXN];
set<int> Set[MAXN];
int n,m,flag;
void intt(){
clean(head,-1);
ecnt=0;
}
void add(int u,int v,int val){
edge[ecnt]=node(v,val,head[u]);
head[u]=ecnt++;
}
int Cmp(Pair a,Pair b){
return a.second>b.second;
}
void BFS(int str){
//cout<<str<<endl;
queue<int> que;que.push(str);
clean(Vis,0);
while(que.size()){
int u=que.front();que.pop();
// if(Vis[u]==2) continue;
Vis[u]=1;//cout<<u<<" : ";
for(int i=head[u];i+1;i=edge[i].nxt){
int temp=edge[i].v;
if(Vis[temp]==0){
// cout<<temp<<" ";
printf("%d %d\n",u,temp);
que.push(temp);Vis[temp]=1;
}
}//cout<<endl;
}
}
int main(){
int n;scanf("%d%d",&n,&m);
int a,b;intt();
for(int i=1;i<=m;++i){
scanf("%d%d",&a,&b);
add(a,b,1);add(b,a,1);
Set[a].insert(b);Set[b].insert(a);
}int stri,strDu=0;
for(int i=1;i<=n;++i){
if(Set[i].size()>strDu){
strDu=Set[i].size();stri=i;
}
}
BFS(stri);
}
F2. Spanning Tree with One Fixed Degree(连通分支+BFS)
题目链接:http://codeforces.com/contest/1133/problem/F2
题目大意:给出一个无向图,然后判断是否存在一个生成树使得该图中的1号节点的度为K。存在输出该生成树,不存在输出"NO"。
思路:判断1号节点的度数是否大于K。小于K输出NO。然后将1号节点从图中删掉,然后找出图中的联通分支。判断连通分支个数是否大于k。大于k输出NO。然后就是必定存在这样一颗生成树。BFS遍历即可。
ACCode:
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define Pair pair<int,int>
#define M_P(a,b) make_pair(a,b)
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// ??
//std::ios::sync_with_stdio(false);
// register
const int MAXN=2e5+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
struct Node{
int v,val,nxt;
Node(int _v=0,int _val=0,int _nxt=0){
v=_v;val=_val;nxt=_nxt;
}
};
Node Edge[MAXN<<1];
int Head[MAXN],Ecnt;
int Ans[MAXN][2],tot;
int Pre[MAXN];
int Deg[MAXN],Vis[MAXN];
queue<Pair> que;
int n,m,k;
void Intt(){
for(int i=1;i<=n+10;++i){
Head[i]=-1;Deg[i]=0;Vis[i]=0;
Pre[i]=i;
}tot=0;Ecnt=0;
}
void Add(int u,int v,int val){
Edge[Ecnt]=Node(v,val,Head[u]);
Head[u]=Ecnt++;
}
void BFS(){
while(que.size()){
Pair u=que.front();que.pop();
++tot;Ans[tot][0]=u.first;Ans[tot][1]=u.second;
for(int i=Head[u.second];i+1;i=Edge[i].nxt){
int temp=Edge[i].v;
if(Vis[temp]==0){
Vis[temp]=1;
que.push(make_pair(u.second,temp));
}
}
}
}
void DFS(int u,int fa){
// printf("u=%d fa=%d\n",u,fa);
Pre[u]=fa;Vis[u]=1;
for(int i=Head[u];i+1;i=Edge[i].nxt){
int temp=Edge[i].v;
if(Vis[temp]==0){
DFS(temp,fa);
}
}
}
int main(){
scanf("%d%d%d",&n,&m,&k);
Intt();
for(int i=1;i<=m;++i){
int u,v;scanf("%d%d",&u,&v);
Add(u,v,1);Add(v,u,1);
Deg[u]++;Deg[v]++;
}
if(Deg[1]<k){
printf("NO\n");return 0;
}int cnt=0;
Vis[1]=1;
for(int i=Head[1];i+1;i=Edge[i].nxt){
int temp=Edge[i].v;
if(Vis[temp]==0){//获得子图
DFS(temp,temp);
cnt++;
}
}
// printf("cnt=%d\n",cnt);
if(cnt>k){//有cnt个连通分支
printf("NO\n");return 0;
}
//连通分支<=k,Deg[1]>=k说明连接同一个连通分支有多个边。
//找到每个连通分支的点即可。
for(int i=0;i<=n;++i) Vis[i]=0;
Vis[1]=1;
for(int i=2;i<=n;++i){//连接所有的联通分支
if(Pre[i]==i){
que.push(make_pair(1,i));
Vis[i]=1;
}
}
// for(int i=1;i<=n;++i){
// printf("Vis[%d]=%d\n",i,Vis[i]);
// }
for(int i=Head[1],j=que.size();i+1&&j<k;i=Edge[i].nxt){
int temp=Edge[i].v;
if(Vis[temp]==0){
que.push(make_pair(1,temp));
Vis[temp]=1;++j;
}
}//cout<<"que.size(): "<<que.size()<<endl;
BFS();
printf("YES\n");
for(int i=1;i<=tot;++i){
printf("%d %d\n",Ans[i][0],Ans[i][1]);
}
}