Codeforces Round #544 (Div. 3) 题解
Codeforces Round #544 (Div. 3)
D. Zero Quantity Maximization
题目链接:https://codeforces.com/contest/1133/problem/D
题意:
给出ai,bi,然后让你确定一个数d,令ci=d*ai+bi,问怎么确定这个d,有最多的ci为0。
题解:
这个题其实不难,但是我没做起,哎,初中数学没学好啊。。其实做法就是map+pair就行了。
但是这里要注意一个问题,就是当ai=bi=0的时候,d是可以任意取值的,可以对其它情况下ci为0的个数作贡献。就是这里坑了我好久。
代码如下:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 2e5+5; ll a[N],b[N],c[N],d[N],f[N]; ll n,k; map <pair<ll,ll>,ll>mp; int main(){ ios::sync_with_stdio(false);cin.tie(0); cin>>n; int ans=0; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++) cin>>b[i]; int cnt = 0; for(int i=1;i<=n;i++){ ll g=__gcd(abs(a[i]),abs(b[i])); if(b[i]==0 && a[i]==0){ cnt++; continue ; }else if(b[i]==0){ ans++; continue ; }else if(a[i]==0){ continue ; } a[i]/=g;b[i]/=g; c[i]=abs(a[i]);d[i]=abs(b[i]); if((a[i]<0&&b[i]>0) ||(a[i]>0&&b[i]<0)){ c[i]=-c[i],d[i]=abs(d[i]); } } for(int i=1;i<=n;i++){ if(b[i]==0||a[i]==0) continue ; mp[make_pair(c[i],d[i])]++; if(mp[make_pair(c[i],d[i])]>ans){ ans=mp[make_pair(c[i],d[i])]; } } cout<<ans+cnt; return 0; }
E. K Balanced Teams
题目链接:https://codeforces.com/contest/1133/problem/E
题意:
给出n个人的姿势水平ai,然后让你最多分成k个组,并且满足每个组里面人的姿势水平相差不超过5,问最多能分多少个学生在组里面。
题解:
排下序然后考虑动态规划。到第i个学生的时候,他可以不被加入分组中,也可以和前面的人一组,设dp[i][j]为前i个人,划分j组时最多的学生。
那么转移就是dp[i][j]=max{dp[i-1][j],dp[k][j-1]+i-k+1}。这里k是往前枚举的,但是其实并不需要这么枚举,只需要找到>=ai-5的第一个位置,从那个位置转移就行了。假设那个位置为p,之后从p+x转移答案不会比从p转移更优的。这个自己yy一下应该还是比较容易相通的吧。
具体见代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 5005; int n,k; int a[N]; int dp[N][N],l[N]; int main(){ ios::sync_with_stdio(false);cin.tie(0); cin>>n>>k; for(int i=1;i<=n;i++) cin>>a[i]; sort(a+1,a+n+1); for(int i=1;i<=n;i++){ int tmp = lower_bound(a+1,a+n+1,a[i]-5)-a; l[i]=tmp-1; } for(int i=1;i<=n;i++){ for(int j=1;j<=i;j++){ dp[i][j]=dp[i-1][j]; dp[i][j]=max(dp[i][j],dp[l[i]][j-1]+i-l[i]); } } int ans = 0; for(int i=1;i<=k;i++) ans=max(ans,dp[n][i]); cout<<ans; return 0; }
F1. Spanning Tree with Maximum Degree
题目链接:https://codeforces.com/contest/1133/problem/F1
题意:
给出一个无向图,然后让你求出这个无向图度数最大的一颗生成树。
题解:
找到度数最大的那个点,然后先把与这个点相连的那些边全部加入生成树中,最后再求生成树就好了。
证明的话,可以这样想,假如我们选的点是u,有两个与其相连的点为v1,v2,假如v1与v2孤立,那么<u,v1>与<u,v2>加入生成树肯定没问题的;如果v1与v2不经过u可以连通,那么<u,v1>,<u,v2>加入生成树中也没问题,不会出现最后没有生成树的情况(自己yy一下吧,感觉有点说不清楚)。
具体见代码吧:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 2e5+5; int n,m; struct Edge{ int u,v,w; bool operator < (const Edge &A)const{ return w<A.w; } }e[N]; int f[N],d[N],vis[N]; int find(int x){ return f[x]==x?f[x]:f[x]=find(f[x]); } int main(){ ios::sync_with_stdio(false);cin.tie(0); cin>>n>>m; int mx=0,p; for(int i=1;i<=m;i++){ int u,v; cin>>u>>v; e[i].u=u;e[i].v=v; d[u]++;d[v]++; if(d[u]>mx){ mx=d[u]; p=u; } if(d[v]>mx){ mx=d[v]; p=v; } } for(int i=0;i<=n+1;i++) f[i]=i; for(int i=1;i<=m;i++){ int u=e[i].u,v=e[i].v; if(u==p||v==p){ int fx=find(u),fy=find(v); f[fx]=fy;vis[i]=1; } } for(int i=1;i<=m;i++){ int fx=find(e[i].u),fy=find(e[i].v); if(fx==fy) continue ; f[fx]=fy;vis[i]=1; } for(int i=1;i<=m;i++) if(vis[i]) cout<<e[i].u<<" "<<e[i].v<<'\n'; return 0; }
F2. Spanning Tree with One Fixed Degree
题目链接:https://codeforces.com/contest/1133/problem/F2
题意:
给出一个无向图和D,要求你求出一颗1结点度数为D的生成树。
题解:
思想还是类似于上面一道题吧,考虑所有与1结点连边的边。我们首先考虑那些必须加入的边,什么边算作必须加入的呢?
假如我们先不考虑与1相连的边,在其它点中求生成树,那么最后会形成一个森林,每个连通块都需要一条边与1号结点相连。通过这个就比较容易计算出必须加入的边。
然后再根据具体D的值,考虑加入与1号点相连的其它边,这样并不会影响它最终是否会形成一个生成树。
代码如下:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 2e5+5; int n,m,k; struct Edge{ int u,v; }e[N]; int f[N],vis[N]; int find(int x){ return f[x]==x?f[x]:f[x]=find(f[x]); } void init(){ for(int i=0;i<=n;i++) f[i]=i; } int main(){ //ios::sync_with_stdio(false);cin.tie(0); cin>>n>>m>>k; init(); for(int i=1;i<=m;i++){ int u,v; cin>>u>>v; e[i].u=u;e[i].v=v; if(u==1 || v==1) continue ; int fx=find(u),fy=find(v); if(fx==fy) continue ; f[fx]=fy; } int need = 0; for(int i=1;i<=m;i++){ int u=e[i].u,v=e[i].v; if(u==1 ||v==1){ int fx=find(u),fy=find(v); if(fx!=fy){ f[fx]=fy; need++; vis[i]=2; }else{ vis[i]=1; } } } if(need>k) return puts("NO"),0; k-=need; init(); for(int i=1;i<=m;i++){ if(vis[i]!=2) continue ; int u=e[i].u,v=e[i].v; int fx=find(u),fy=find(v); f[fx]=fy; } for(int i=1;i<=m;i++){ if(k==0) break ; if(vis[i]==1){ k--; int u=e[i].u,v=e[i].v; int fx=find(u),fy=find(v); f[fx]=fy; vis[i]=3; } } if(k>0) return puts("NO"),0; puts("YES"); for(int i=1;i<=m;i++){ if(e[i].u==1 || e[i].v==1) continue ; int fx=find(e[i].u),fy=find(e[i].v); if(fx!=fy){ f[fx]=fy; vis[i]=3; } } for(int i=1;i<=m;i++){ if(vis[i]>=2) cout<<e[i].u<<" "<<e[i].v<<'\n'; } return 0; }
重要的是自信,一旦有了自信,人就会赢得一切。