前言
这场由于大号都不算分,于是开新号打,开场还算顺利,但是由于D题的坑点较多,有点慌,导致E题也开始乱提交,最后没时间做F2。打div3打成这样是不应该的。
biu-biubiu
r
a
t
i
n
g
+
=
168
rating+=168
rating+=168 1500->1668
A. Middle of the Contest
题意
输出两个时间的中间时间。
做法
由于两个时间在同一天,直接转换成分钟取平均值就可以。
代码
#include<stdio.h>
int main()
{
int h1,m1,h2,m2;
scanf("%d:%d",&h1,&m1);
scanf("%d:%d",&h2,&m2);
printf("%02d:%02d\n",(h1*30+h2*30+(m1+m2)/2)/60,(h1*30+h2*30+(m1+m2)/2)%60);
return 0;
}
B. Preparation for International Women’s Day
题意
给你n个数,两个数成对取出,求最多可以取出多少对和是k的倍数。
1
≤
n
≤
2
×
1
0
5
1 \leq n \leq 2 \times 10^5
1≤n≤2×105
1
≤
k
≤
100
1 \leq k \leq 100
1≤k≤100
做法
对于每个数只保存对k取模之后的余数即可,之后对于每个余数与对应的余数匹配即可。
要特判
0
0
0和余数等于
k
/
2
k/2
k/2的时候。
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 2e5+5;
int d[maxn];
int sum[maxn];
int main()
{
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&d[i]);
sum[d[i]%k]++;
}
int ans=sum[0]/2;
for(int i=1;i<=k/2;i++)
{
if(i==k-i) ans=ans+sum[i]/2;
else ans=ans+min(sum[i],sum[k-i]);
}
printf("%d\n",ans*2);
return 0;
}
C. Balanced Team
题意
给你 n n n个数字,从中选出尽量多的数字,使这些数中最大值与最小值的差不超过 5 5 5.
做法
首先将数组排序,二分找到每个值能向右伸展的最长长度即可。
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 2e5+5;
int a[maxn];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+1+n);
int ans=1;
for(int i=1;i<=n;i++)
{
int pos=upper_bound(a+1,a+1+n,a[i]+5)-a;
ans=max(ans,pos-i);
}
printf("%d\n",ans);
return 0;
}
D. Zero Quantity Maximization
题意
给你两个长度为
n
n
n的数组
a
a
a,
b
b
b,
c
i
=
a
i
×
d
+
b
i
c_i = a_i \times d +b_i
ci=ai×d+bi,现在找到一个
d
d
d使尽量多的
c
i
c_i
ci为
0
0
0。
1
≤
n
≤
1
0
5
1 \leq n \leq 10^5
1≤n≤105
−
1
0
9
≤
a
i
,
b
i
≤
1
0
9
-10^9 \leq a_i,b_i \leq10^9
−109≤ai,bi≤109
做法
设 c i = 0 c_i=0 ci=0,那么 d = − b i a i d=-\frac{b_i}{a_i} d=−aibi,只需要看哪个d出现次数最多即可,这里我怕被卡精度,于是存分数约分后的最简形式即可,这里要注意 a i = 0 , b i = 0 a_i=0,b_i=0 ai=0,bi=0等情况。
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
typedef pair<int,int> pii;
const int maxn = 2e5+5;
map<pii,int> mp;
int a[maxn],b[maxn];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
int ans=0;
int tmp=0;
for(int i=1;i<=n;i++)
{
if(a[i]==0&&b[i]==0)
{
tmp++;
continue;
}
else if(a[i]==0) continue;
if(b[i]==0)
{
mp[pii(0,1)]++;
ans=max(ans,mp[pii(0,1)]);
continue;
}
int up=-b[i]/__gcd(a[i],b[i]);
int down=a[i]/__gcd(a[i],b[i]);
if(up<0)
{
up=up*-1;
down=down*-1;
}
mp[pii(up,down)]++;
ans=max(ans,mp[pii(up,down)]);
}
printf("%d\n",ans+tmp);
return 0;
}
E. K Balanced Teams
题意
给你n个数,分成k组,要求每组内最大值与最小值的差值不超过5。求k组最多可以放多少个数。
1
≤
n
,
k
≤
5000
1 \leq n,k \leq 5000
1≤n,k≤5000
做法
首先对数组排序,我们可以预处理每个数最多可以向左扩展的长度。
之后我们用
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示前i个数分为j组最多可以放多少个数。
对于每个i,一定是从之前预处理的位置转移过来,因为一段应该放尽量多的值。
我们设位置
i
i
i能够扩展的最左位置为
l
[
i
]
l[i]
l[i]。那么转移方程为:
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
−
1
]
[
j
]
,
d
p
[
i
]
[
j
−
1
]
,
d
p
[
l
[
i
]
−
1
]
[
j
−
1
]
+
i
−
l
[
i
]
+
1
)
dp[i][j]=max(dp[i-1][j],dp[i][j-1],dp[l[i]-1][j-1]+i-l[i]+1)
dp[i][j]=max(dp[i−1][j],dp[i][j−1],dp[l[i]−1][j−1]+i−l[i]+1)
最后
d
p
[
n
]
[
k
]
dp[n][k]
dp[n][k]便是答案。
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 5005;
int a[maxn],l[maxn];
int dp[maxn][maxn];
int main()
{
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+1+n);
dp[0][0]=0;
for(int i=1;i<=n;i++) l[i]=lower_bound(a+1,a+1+n,a[i]-5)-a;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=i;j++)
{
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
dp[i][j]=max(dp[i][j],dp[l[i]-1][j-1]+i-l[i]+1);
}
}
printf("%d\n",dp[n][k]);
return 0;
}
F1. Spanning Tree with Maximum Degree
题意
给你 n n n个点 m m m条边的无向联通图,找出一棵生成树,使度最大的点的度最大。
1
≤
n
,
m
≤
1
0
5
1 \leq n,m \leq 10^5
1≤n,m≤105
做法
首先度最大的点一定等于原图中度最大的点的度,那么我们只需要找到原图中度最大的点,由这个点向外 b f s bfs bfs即可。
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
typedef pair <int, int> pii;
const int maxn = 2e5+5;
#define Se second
#define Fi first
#define pb push_back
int vis[maxn];
vector<int>G[maxn];
vector<pii> ans;
int in[maxn];
void bfs(int rt)
{
vis[rt]=1;
queue<int> q;
q.push(rt);
while(!q.empty())
{
int tp=q.front();
q.pop();
for(int i=0;i<G[tp].size();i++)
{
int to=G[tp][i];
if(vis[to]) continue;
vis[to]=1;
ans.pb(pii(tp,to));
q.push(to);
}
}
}
int main()
{
int u,v,n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
G[u].pb(v);
G[v].pb(u);
in[u]++;
in[v]++;
}
int maxx=0;
int pos=0;
for(int i=1;i<=n;i++)
{
if(in[i]>maxx)
{
maxx=in[i];
pos=i;
}
}
bfs(pos);
for(int i=0;i<ans.size();i++) printf("%d %d\n",ans[i].Fi,ans[i].Se);
return 0;
}
F2. Spanning Tree with One Fixed Degree
题意
给你 n n n个点 m m m条边的无向联通图,找出一棵生成树,使 1 1 1这个点的度 = d =d =d。
1
≤
n
,
m
≤
1
0
5
1 \leq n,m \leq 10^5
1≤n,m≤105
做法
首先我们把 1 1 1这个点先拿出来,如果 1 1 1的度最初就小于 d d d,答案一定不存在,否则对除 1 1 1这个点之外剩下的图求连通分量,并记录每个连通分量之内有哪些点与 1 1 1相连,之后为保证联通,每个连通分量一定至少和 1 1 1连一条边,之后如果此时 1 1 1的度已经超过 d d d,则答案不存在,否则将多余的度与那些之前没连过而且与 1 1 1有边的点相连即可。
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<string.h>
using namespace std;
typedef pair <int, int> pii;
const int maxn = 2e5+5;
#define Se second
#define Fi first
#define pb push_back
vector<int>G[maxn];
vector<int>dsu[maxn];
vector<int>one[maxn];
vector<pii> ans;
int n,m,d,in[maxn];
int vis[maxn];
int tot;
void dfs(int x)
{
dsu[tot].pb(x);
vis[x]=1;
for(int i=0;i<G[x].size();i++)
{
int to=G[x][i];
if(vis[to]) continue;
if(to==1)
{
one[tot].pb(x);
continue;
}
dfs(to);
}
}
int main()
{
int u,v;
scanf("%d%d%d",&n,&m,&d);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
in[u]++;
in[v]++;
G[u].pb(v);
G[v].pb(u);
}
if(in[1]<d) return 0*puts("NO");
for(int i=2;i<=n;i++)
{
if(!vis[i])
{
++tot;
dfs(i);
}
}
if(tot>d) return 0*puts("NO");
memset(vis,0,sizeof(vis));
queue<int> q;
vis[1]=1;
for(int i=1;i<=tot;i++)
{
int b=one[i].back();
ans.pb(pii(1,b));
vis[b]=1;
q.push(b);
one[i].pop_back();
d--;
}
for(int i=1;i<=tot;i++)
{
while(d>0&&one[i].size()>0)
{
int b=one[i].back();
ans.pb(pii(1,b));
vis[b]=1;
q.push(b);
one[i].pop_back();
d--;
}
}
while(!q.empty())
{
int tp=q.front();
q.pop();
for(int i=0;i<G[tp].size();i++)
{
int to=G[tp][i];
if(vis[to]) continue;
ans.pb(pii(tp,to));
vis[to]=1;
q.push(to);
}
}
puts("YES");
for(int i=0;i<ans.size();i++) printf("%d %d\n",ans[i].Fi,ans[i].Se);
return 0;
}