A - Middle of the Contest
题意:给出两个时间,保证在同一天,求中间时刻
思路:直接转换为一天的第多少分钟,求平均,再转换回小时:分钟的形式。
int t,n,m;
char buffer[10];
void init(){}
int main(){
init();
int t1,t2;
scanf("%s",&buffer[0]);
buffer[0]-='0';
buffer[1]-='0';
buffer[3]-='0';
buffer[4]-='0';
t1=(buffer[0]*10+buffer[1])*60+(buffer[3]*10+buffer[4]);
scanf("%s",&buffer[0]);
buffer[0]-='0';
buffer[1]-='0';
buffer[3]-='0';
buffer[4]-='0';
t2=(buffer[0]*10+buffer[1])*60+(buffer[3]*10+buffer[4]);
t1=(t1+t2)/2;
buffer[0]='0'+(t1/60)/10;
buffer[1]='0'+(t1/60)%10;
buffer[3]='0'+(t1%60)/10;
buffer[4]='0'+(t1%60)%10;
printf("%s",buffer);
return 0;
}
B - Preparation for International Women's Day
题意:给 (n) 盒子,每个盒子有 (d_{i}) 个物品。对这些盒子两两配对,问最多有多少个盒子可以参与两两配对,满足两盒子中物品相加为 (k) 的倍数。
思路:将盒子内物品对 (k) 取模,若满足取模后的数相加为 (k) ,则配对后正好为 (k) 的倍数。然后循环看每个余数的 (i) 与 (k-i) 的最小值,就是当前余数的最大匹配的数量。注意对(k/2)和 (0) 进行特判。
int num[105];//num[i]表示余数i出现的次数。
int t,n,m,k,tp;
int main(){
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++){
scanf("%d",&tp);
num[tp%k]++;
}
int ans=num[0]/2;
for(int i=1;i<=k/2;i++){
if(i!=k-i)ans+=min(num[i],num[k-i]);
else ans+=num[i]/2;
}
printf("%d",ans*2);
return 0;
}
C - Balanced Team
题意:给出 (n) 个人,每个人有各自的能力值 (a_{i}) ,现在要在 (i) 个中取尽量多的人构成一组,并且组内人最大能力值与最小能力值之差应不大于5,问组内人数最多是多少。
思路:
方法1:先对能力值进行排序,然后用双指针尺取。左指针枚举组内最低人的能力,右指针指向相对左指针来说,能取到的最高的人。
方法2:用map记录每一个能力值出现的人的次数,然后枚举每一个最低能力值,对每一个能力值 (a_{i}) ,求出(mp[a_{i}]+mp[a_{i+1}]+mp[a_{i+2}]+mp[a_{i+3}]+mp[a_{i+4}]+mp[a_{i+5}])的值,并求出最值。
unordered_map<int,int> mp;
int t,n,m;
ll tp;
std::vector<int> stu;
void init(){}
int main(){
init();
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%lld",&tp);
if(mp[tp]==0)stu.push_back(tp);//每个能力值最后只求一次
mp[tp]++;
}
ll ans=0;
for(int i=0;i<stu.size();i++){
tp=0;
for(int j=0;j<=5;j++){
tp+=mp[stu[i]+j];
}
ans=max(ans,tp);
}
printf("%lld
",ans);
return 0;
}
D - Zero Quantity Maximization
题意:
给出 (a_{i}) ,(b_{i}) ,找到一个实数 (d) (注意不一定是整数),使得由 (a_{i},b_{i}) ,用 公式(c_{i}=a_{i}cdot d + b_{i}) 生成出的数组(c_{i}) 中,(c_{i} = 0) 的数量最多。
思路:
首先可由原式得当 (d=-frac{b_{i}}{a_{i}}) 时,(c_{i}=0) 。故,我们可以求出所有的 (frac {b_{i}} {a_{i}}) 值,统计出这些值中出现最多的那个值,则当(d) 等于出现次数最多的那个值时,满足(d=-frac{b_{i}}{a_{i}}) 式的(a_{i},b_{i}) 最多,则 (c_{i}) 中 0 最多。由于每个分数可以唯一表示为最简分数,所以我们可以统计 (<frac{b_{i}}{gcd(a,b)},frac{a_{i}}{gcd(a,b)}>) 二元组来统计 (frac {b_{i}} {a_{i}}),也可以用(b_{i}cdot 1e^9+a_{i})的单个longlong整数来统计。特别注意,对a=0,b=0需要特殊处理。当(a=0) 且 (b=0) 时,无论 (d) 如何取值都满足,应当直接加入答案。当(a eq0)且(b = 0) 时,d无论取何值都不满足。当(a eq0)且(b=0)时,(b)无论是何值,都是等价的,应当统计对应成同一个(d) 。
ll t,n,m;
ll gcd(ll a,ll b){
return a%b==0? b:gcd(b,a%b);
}
struct xy{
ll up,down;
};
map <pair<ll,ll>,ll> mp;
void init(){}
ll a[maxn],b[maxn],up[maxn],down[maxn];
int main(){
init();
scanf("%lld",&n);
for(ll i=0;i<n;i++){
scanf("%lld",&a[i]);
}
for(ll i=0;i<n;i++){
scanf("%lld",&b[i]);
}
ll ans=0,maxx=0;
for(ll i=0;i<n;i++){
pair<ll,ll> tp;
if(a[i]==0&&b[i]==0){
ans++;
continue;
}
if(b[i]==0){
tp.first=0;
tp.second=1;
maxx=max(maxx,++mp[tp]);
continue;
}
if(a[i]==0){
continue;
}
ll ggcd=gcd(b[i],a[i]);
tp.first=b[i]/ggcd;
tp.second=a[i]/ggcd;
maxx=max(maxx,++mp[tp]);
}
printf("%lld
",ans+maxx);
return 0;
}
E - K Balanced Teams
题意:给出n个人,每个人有能力 (a_{i}) ,现在要选出一部分人分成至多 (k) 组,要求组内人的能力值只差小于等于 (5) ,问最多能将多少人划分为组内。
思路:二维dp,(dp[i][j]) 表示前 (i) 个人分了 (k) 组的情况下最多能将多少人划入组内。
首先给能力值进行排序,再进行dp。
转移方程为(dp[i][j]=max(dp[i-1][j],dp[i-x][j-1]),(其中x需要满足a[i-x]-a[i]le 5)) 因为对能力值排序过了,所以可以用单调队列来动态维护(dp[i-x][j-1])的值,也可以用其他方法。因为从尽量靠前转移过来,结果是最优的,所以可以只枚举从最尽量最左转移过来,维护一个左指针。因为左指针始终是单调的,即使直接扫,也能够达到O(n)的复杂度。最后找出 (i=n) 列中最大的dp值就是答案。
const int N=5001;
int a[N],b[N],dp[N][N],n,k;
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+1+n);
for(int i=1;i<=n;i++){
for(int j=i;j>=1;j--)
if(a[j]>=a[i]-5)b[i]=j-1;
for(int j=1;j<=k;j++)
dp[i][j]=max(dp[i-1][j],dp[b[i]][j-1]+i-b[i]);
}
cout<<dp[n][k]<<endl;
}
F - Spanning Tree with Maximum Degree
题意:求出原图中的一个生成树,使得该生成树中最大度数的节点的度数是所有生成树中最大的。
思路:找出原图中度数最大的点,将这个点的所有边先全部加入生成树,保证度数最大,然后对剩下的边集求整个图的生成树。
typedef long long ll;
const int maxn=2e5+50;
const int maxm=1e5+50;
const ll inf=0x7fffffff;
int fa[maxn];
int find(int x){
return (fa[x] == x) ? x : (fa[x] = find(fa[x]));
}
bool unio(int x, int y){
int tx = find(x), ty = find(y);
if (tx != ty) {
fa[tx] = ty;
return 1;
}
return 0;
}
std::vector< pair<int,int> > g,ans;
int t,n,m;
int in[maxn];
void init(int n,int m){
for(int i=0;i<=n;i++){
fa[i]=i;
in[i]=0;
}
}
int main(){
scanf("%d%d",&n,&m);
init(n,m);
int u,v,maxx=0,maxi=0;
for(int i=0;i<m;i++){
scanf("%d%d",&u,&v);
g.push_back(make_pair(u,v));//图的所有边
//统计度数
in[u]++;
in[v]++;
//找出最大的度数的点。
if(in[u]>maxx){
maxx=in[u];
maxi=u;
}
if(in[v]>maxx){
maxx=in[v];
maxi=v;
}
}
for(int i=0;i<m;i++){
if(g[i].first==maxi||g[i].second==maxi){
if(unio(g[i].first,g[i].second))
ans.push_back(g[i]);
}//将最大的度数的点的所有边连起来。
}
for(int i=0;i<m;i++){
if(unio(g[i].first,g[i].second)){
ans.push_back(g[i]);//生下的边跑生成树连起来
}
}
for(int i=0;i<ans.size();i++){
printf("%d %d
",ans[i].first,ans[i].second);
}
return 0;
}