A
思路
做法显然,但是需要注意一些小的细节:
①不能输出如"2:2"这样的时间,必须输出"02:02"这样的时间;
②中间的冒号是":",而不是“:”。
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
int a,b,c,d,n1,n2,n,aa,bb;
char x;
signed main()
{
cin>>a>>x>>b>>c>>x>>d;
n1=a*60+b;
n2=c*60+d;
n=(n1+n2)/2;
aa=n/60,bb=n%60;
if (aa<10) cout<<0<<aa;
else cout<<aa;
cout<<x;
if (bb<10) cout<<0<<bb;
else cout<<bb<<endl;
return 0;
}
B
思路
用一个桶, b i b_i bi记录下除以 k k k余 i i i的数的数量。
显然,若 i + j i+j i+j是 k k k的倍数,那么可以送给同一个Polycarp女友的盒子对就可以配成 m i n ( b i , b j ) min(b_i,b_j) min(bi,bj)组,即可配成 2 m i n ( b i , b j ) 2min(b_i,b_j) 2min(bi,bj)个盒子。
所以,直接枚举 i i i,并求出 j j j使得 i + j i+j i+j为 k k k的倍数,最后用上面所说的方法求一下就可以啦。注意特判一下 i = j i=j i=j的情况,可能配成 b i − ( b i m o d 2 ) b_i-(b_i\ mod\ 2) bi−(bi mod 2)个盒子。
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,k,ans;
int a[200005],b[105];
signed main()
{
cin>>n>>k;
for (int i=1;i<=n;i++) cin>>a[i];
for (int i=1;i<=n;i++) b[a[i]%k]++;
for (int i=0;i<=k/2;i++)
{
int o=(k-i)%k;
if (i==o) ans+=(b[i]/2)*2;
else ans+=min(b[i],b[o])*2;
}
cout<<ans<<endl;
return 0;
}
C
思路
暴力找显然会超时。
那么怎么办呢?首先按升序排序。然后,对于每个 i i i向后找最后一个与 a i a_i ai之差不大于5的数的位置;记这个位置为 p p p,那么就能形成人数为 p − i + 1 p-i+1 p−i+1的BT(Balanced Team)。
注意"向后找最后一个与 a i a_i ai之差不大于5的数的位置"可以用二分来完成。
其时间复杂度为 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n),不会超时。
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,ans=-1,last;
int a[200005];
int find(int l,int r,int k)
{
if (l+1==r||l==r)
{
if (a[r]-k>5) return last;
else return max(r,last);
}
int mid=(l+r)>>1;
if (a[mid]-k<=5)
{
last=mid;
return find(mid,r,k);
}
else return find(l,mid,k);
}
signed main()
{
cin>>n;
for (int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
for (int i=1;i<=n;i++) last=-1,ans=max(ans,find(i,n,a[i])-i+1);
cout<<ans<<endl;
return 0;
}
D
好惨啊~WA了7次
思路
首先,观察这个式子: d a i + b i = c i da_i+b_i=c_i dai+bi=ci。
将 c i = 0 c_i=0 ci=0带入,得
d
a
i
+
b
i
=
0
da_i+b_i=0
dai+bi=0
d
a
i
=
−
b
i
da_i=-b_i
dai=−bi
d
=
−
b
i
a
i
d=\frac {-b_i} {a_i}
d=ai−bi
所以,对于每个 i i i求出满足要求的 d d d;最后数一数最后有多少个不同的 d d d即可。
这么简单?
怎么可能!
①哇哇!RE!
显然,当
a
i
=
0
a_i=0
ai=0且
b
i
≠
0
b_i≠0
bi=0时,是不存在
d
d
d的,这种情况直接舍去;
另外,当
a
i
=
b
i
=
0
a_i=b_i=0
ai=bi=0时,
d
d
d可以随便取值;假设这种情况有
z
e
r
o
zero
zero个,并暂时忽略这种情况,最后将答案加上
z
e
r
o
zero
zero就是最终的答案。
②哇哇!WA!
您的精度出现了问题。
如何控制精度呢?我们可以将分子与分母约分后用map存下。记录下每对约分后分子与分母的相同对数并加上
z
e
r
o
zero
zero就是最终的答案。
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,ans=-1,last;
int a[200005];
int find(int l,int r,int k)
{
if (l+1==r||l==r)
{
if (a[r]-k>5) return last;
else return max(r,last);
}
int mid=(l+r)>>1;
if (a[mid]-k<=5)
{
last=mid;
return find(mid,r,k);
}
else return find(l,mid,k);
}
signed main()
{
cin>>n;
for (int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
for (int i=1;i<=n;i++) last=-1,ans=max(ans,find(i,n,a[i])-i+1);
cout<<ans<<endl;
return 0;
}
E
思路
一道略简单的 d p dp dp题。
状态设计 d p i , j dp_{i,j} dpi,j表示,目前看到 i i i这个人,分 j j j个队时最多能进队的人数。
状态转移显然;设 l a s t last last为 i i i之前最前一个与 i i i之差不大于 5 5 5的数的位置。那么, i i i可以贪心地与 l a s t last last分在一组也可以哪个组都不去。
第一种情况:哪个组都不去。继承上一个状态: d p i − 1 , j dp_{{i-1,}j} dpi−1,j。
第二种情况:与
l
a
s
t
last
last分在一组。显然,位置在
l
a
s
t
+
1
last+1
last+1到
i
i
i的位置均要贪心地选。并且,看到
l
a
s
t
last
last的时候必须贪心地选
j
−
1
j-1
j−1组,不能选
j
j
j组,否则
a
i
a_i
ai根本进不来,原因是含有
l
a
s
t
last
last的第
j
j
j组中一定会有与
a
i
a_i
ai之差大于5的数。
所以,此时
d
p
i
,
j
=
d
p
l
a
s
t
,
j
−
1
+
(
i
−
l
a
s
t
)
dp_{i,j}=dp_{last,{j-1}}+(i-last)
dpi,j=dplast,j−1+(i−last)。
综上所述,状态转移就是:
d
p
i
,
j
=
m
a
x
(
d
p
i
−
1
,
j
,
d
p
l
a
s
t
,
j
−
1
+
(
i
−
l
a
s
t
)
)
dp_{i,j}=max(dp_{i-1,j},dp_{last,{j-1}}+(i-last))
dpi,j=max(dpi−1,j,dplast,j−1+(i−last))
注意,我们不需要用二分找 l a s t last last,朴素找也会超时。总时间复杂度为 O ( n ( n + m ) ) O(n(n+m)) O(n(n+m))。
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=505;
int n,m,ans=-1;
int a[maxn],dp[maxn][maxn];
signed main()
{
cin>>n>>m;
for (int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
dp[1][1]=1;
for (int i=1;i<=n;i++)
{
int last=i;
while (abs(a[last]-a[i])<=5&&last>=1) last--;
for (int j=1;j<=m;j++) dp[i][j]=max(dp[i-1][j],dp[last][j-1]+(i-last));
}
for (int i=1;i<=m;i++) ans=max(ans,dp[n][i]);
cout<<ans<<endl;
return 0;
}
F1
唉,心态真TM炸了,比赛的时候绞尽脑汁就是想不出来;比赛后仍然想不出来,重新看题才发现本菜鸡把题目看错了。
唉,差一点就进前 15 15 15了QAQ
题面(罚自己写)
给定一个无向联通图,请找出它的一个生成树使得该树中所有节点的度数的最大值最大,并输出该树的所有边。
思路
显然,我们要贪心地取那个原图中度数最大的节点与其所有边。然后,在保证选出来的是一棵树的情况下,每次任意加边。
注意判断其是否为树(即无环)可以用并查集来完成。
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,m,u,v,maxv=-1,pos;
int de[200005],father[200005];
struct edge
{
int u,v;
}e[400005];
int find(int x)
{
if (x!=father[x]) father[x]=find(father[x]);
return father[x];
}
signed main()
{
cin>>n>>m;
for (int i=1;i<=n;i++) father[i]=i;
for (int i=1;i<=m;i++)
{
cin>>e[i].u>>e[i].v;
de[e[i].u]++,de[e[i].v]++;
}
for (int i=1;i<=n;i++)
{
if (de[i]>maxv)
{
maxv=de[i];
pos=i;
}
}
for (int i=1;i<=m;i++)
{
if (e[i].u==pos||e[i].v==pos)
{
cout<<e[i].u<<' '<<e[i].v<<endl;
father[find(e[i].v)]=find(e[i].u);
}
}
for (int i=1;i<=m;i++)
{
if (find(e[i].u)!=find(e[i].v)&&e[i].u!=pos&&e[i].v!=pos)
{
cout<<e[i].u<<' '<<e[i].v<<endl;
father[find(e[i].v)]=find(e[i].u);
}
}
return 0;
}
E2
做不出来咕咕咕~
总结
①并查集三个月没做了~这一次又巩固了一遍;
②动规
d
p
dp
dp增强了一丢丢;
③信心加了一点点。