题意:你可以设D为任意实数,使得D*ai+bi为0的数量最多,并求出数量。
思路:很简单,把每组ai bi,都除以他们的gcd然后把ai bi统一换成ai为正数再hash就可以了,不过有一些ai bi为0的细节,也不难去处理,水题。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e5+10;
map<ll,int>mp,mp2;
int a[maxn],b[maxn],mx,v=1e9+5;
int gcd(int x,int y)
{
if(!x||!y)return max(x,y);
return gcd(y,x%y);
}
int main()
{
int n,res=0,sum=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int j=1;j<=n;j++)scanf("%d",&b[j]);
for(int i=1;i<=n;i++)
{
int x=gcd(abs(a[i]),abs(b[i]));
if(a[i]==0&&b[i]==0)
{
res++;
continue;
}
if(a[i]==0)continue;
if(b[i]==0)
{
sum++;
mx=max(mx,sum);
continue;
}
a[i]/=x,b[i]/=x;
if(a[i]<0)a[i]=-a[i],b[i]=-b[i];
ll cur=1ll*a[i]*v+b[i];
if(1ll*a[i]*b[i]>=0)
mp[cur]++,mx=max(mx,mp[cur]);
else
mp2[cur]++,mx=max(mx,mp2[cur]);
}
cout<<mx+res;
}
思路:给你个序列,你可以从中选择一些数组成 k 个集合,每个集合的所有元素之差不能超过5,求 k 个集合最多能有多少元素 。
思路:先排序,然后用单调队列求出从ai开始最多可以走多长的距离并记录为bi,设d[ i ][ j ]为从第 i 个元素到第 n 个元素中组成 j 个集合的最大值,很明显转移方程:d[ i ][ j ]=max(d[ i+1 ][ j ],d[ i+bi ][j-1]+bi)。
#include<bits/stdc++.h>
using namespace std;
const int maxn=5005;
int d[maxn][maxn],a[maxn],b[maxn];
int q[maxn],h,t;
int main()
{
int n,k,ans=0;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
sort(a+1,a+1+n);
for(int i=n;i;i--)
{
if(h==t)
b[i]=1;
else
{
while(a[q[t]]-a[i]>5&&h>t)t++;
b[i]=h-t+1;
}
q[h++]=i;
}
for(int i=n;i;i--)
for(int j=1;j<=k;j++)
{
d[i][j]=max(d[i+1][j],d[i][j]);
d[i][j]=max(d[i+b[i]][j-1]+b[i],d[i][j]);
ans=max(ans,d[i][j]);
}
printf("%d\n",ans);
}
F1. Spanning Tree with Maximum Degree
题意:让你构造一棵树,使得该树度数最大的节点度数最大。
思路:先找到度数最大的点rt,先把连接rt的边全部连接,然后再用并查集判环去连接剩下的边即可,水题。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e5+10;
vector<int>G[maxn];
int a[maxn],b[maxn],p[maxn],d[maxn];
int find(int x)
{
if(x!=p[x])
p[x]=find(p[x]);
return p[x];
}
int Union(int u,int v)
{
int fu=find(u);
int fv=find(v);
if(fu!=fv)
{
p[fu]=fv;
return 1;
}
return 0;
}
int main()
{
int n,m,rt,mx=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)p[i]=i;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a[i],&b[i]);
d[a[i]]++,d[b[i]]++;
if(d[a[i]]>mx)
mx=d[a[i]],rt=a[i];
if(d[b[i]]>mx)
mx=d[b[i]],rt=b[i];
G[a[i]].push_back(b[i]);
G[b[i]].push_back(a[i]);
}
for(int i=0;i<G[rt].size();i++)
{
printf("%d %d\n",rt,G[rt][i]);
Union(G[rt][i],rt);
}
n-=G[rt].size();
if(n>1)
{
for(int i=1;i<=m;i++)
{
if(Union(a[i],b[i]))
{
printf("%d %d\n",a[i],b[i]);
n--;
if(n==1)return 0;
}
}
}
}
F2. Spanning Tree with One Fixed Degree
题意:要求根节点即1号点度数为k,让你构造一棵树。
思路:先把1号点相连的点全部标记,然后进行第一次连边:枚举所有边u v,如果u v没有同时被标记且均不为根就连接,第二次连边:枚举所有边 u v,如果都被标记了且还需要连接的边>k,就连接,第三次连边:连接1和被标记的节点即可。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10,inf=1e9;
vector<int>G[maxn];
int a[maxn],b[maxn],p[maxn],vis[maxn];
int t1[maxn],t2[maxn],cnt;
int find(int x)
{
if(x!=p[x])
p[x]=find(p[x]);
return p[x];
}
int Union(int u,int v)
{
int fu=find(u),fv=find(v);
if(fu!=fv)
{
if(vis[fu])p[fv]=fu;
else p[fu]=fv;
return 1;
}
return 0;
}
int main()
{
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)p[i]=i;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a[i],&b[i]);
G[a[i]].push_back(b[i]);
G[b[i]].push_back(a[i]);
}
for(int i=0;i<G[1].size();i++)
vis[G[1][i]]=1;
if(n-1>k)
for(int i=1;i<=m;i++)
{
int fa=find(a[i]),fb=find(b[i]);
if(vis[fa]&&vis[fb])continue;
if(a[i]!=1&&b[i]!=1&&Union(a[i],b[i]))
{
t1[++cnt]=a[i],t2[cnt]=b[i];
n--;
if(n-1==k)
break;
}
}
if(n-1>k)
for(int i=1;i<=m;i++)
{
int fa=find(a[i]),fb=find(b[i]);
if(vis[fa]&&vis[fb])
{
if(a[i]!=1&&b[i]!=1&&Union(a[i],b[i]))
{
t1[++cnt]=a[i],t2[cnt]=b[i];
n--;
if(n-1==k)
break;
}
}
}
for(int i=0;i<G[1].size();i++)
if(Union(1,G[1][i]))
{
t1[++cnt]=1,t2[cnt]=G[1][i];
n--,k--;
if(n==1||!k)break;
}
if(n>1)puts("NO"),exit(0);
else
{
puts("YES");
for(int i=1;i<=cnt;i++)
printf("%d %d\n",t1[i],t2[i]);
}
}