第4题
题目链接:https://codeforces.com/contest/1230/problem/D
题目大意:又一个教练,手下有n个队员,每个队员有自己的技能用a[i]表示,就是如果a[i]=6,那么二进制下表示为110,所以他掌握了两个技能,然后每个人有掌握技能水平,用b[i]表示。如果一个人掌握的技能另一个人没有掌握,这个人就可以认为自己比较优秀。教练有m个人为一组出去比赛,但是这m个人中不能有那种觉得自己比其他人都优秀的人,问小组的最大技能水平是多少。
思路:首先知道如果m个人中,有一个人觉得自己比另外m-1个人都优秀的话,那这个人直接就去掉。先预处理出“优秀关系”,然后每次找到最优秀的那个,看看是不是觉得自己比其他人都优秀,是的话去掉,不然就可以停下来了。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[7010],b[7010][70],c[7010];
ll val[7070];
int vis[7010];
int zzz[7010][7010];
map<ll,ll>mp;
struct S
{
ll val,num,zz;
}p[7070];
int main()
{
ll n,i,j,k,v,sum=0;
scanf("%lld",&n);
for(i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
if(mp[a[i]]==0)mp[a[i]]=++sum;
p[i].zz=mp[a[i]];
for(j=60;j>=0;j--)
{
if(a[i]==0)b[i][j]=0;
else
{
b[i][j]=a[i]&1; //处理出每个人掌握的技能
a[i]/=2;
}
}
}
for(i=1;i<=n;i++)
{
for(j=i+1;j<=n;j++)
{
if(i==j)continue;
int fl1=0,fl2=0;
for(k=0;k<=60;k++)
{
if(b[i][k]==1&&b[j][k]==0)fl1=1;
else if(b[i][k]==0&&b[j][k]==1)fl2=1;
}
if(fl1==1)zzz[p[i].zz][p[j].zz]=1; //把人跟人之间的比较关系标一下
if(fl2==1)zzz[p[j].zz][p[i].zz]=1;
p[i].num+=fl1;
p[j].num+=fl2;
}
}
ll ans=0;
for(i=1;i<=n;i++)
{
scanf("%lld",&v);
p[i].val=v;
ans+=v;
}
ll pos,num=0;
for(i=1;i<=n;i++)
{
ll cc=0,c=0;
pos=-1;
for(j=1;j<=n;j++) //找出最优秀的
{
if(vis[j])continue;
if(p[j].num>cc)
{
cc=p[j].num;
c=p[j].val;
pos=j;
}
else if(p[j].num==cc)
{
if(p[j].val<c)
{
c=p[j].val;
pos=j;
}
}
}
if(pos==-1)break;
vis[pos]=1;
num++;
if(p[pos].num==n-i) //如果最优秀的关系跟剩下的人数一样多,踢掉
{
ans-=p[pos].val;
for(j=1;j<=n;j++)
{
if(vis[j])continue;
if(zzz[p[j].zz][p[pos].zz]==1)
p[j].num--;
}
}
else break;
}
if(pos==-1)
{
if(n-num==1)cout<<0;
else cout<<ans;
}
else cout<<ans<<endl;
}
4题做完没时间看第5题了,真是个弟弟
第5题
题目大意:个n个点,每个点都有一个值,n-1一条边,保证是连通图,问从每个点出发到叶子节点的gcd值的和,更仔细的可以看一下对于样例1的解释。
思路:就是dfs,然后记录下每个点对应的每个gcd值的个数,最后计算和。(借鉴了一下别人的做法)。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<deque>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#include <string>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
vector<int>v[100010];
ll a[100010];
map<ll,ll>mp[100010];
ll gcd(ll a,ll b)
{
if(b==0)return a;
return gcd(b,a%b);
}
ll ans;
void dfs(int now,int pre)
{
for(auto it:mp[now])
ans=(ans+it.first*it.second)%mod; //把自己加上
for(auto it:v[now])
{
if(it==pre)continue;
mp[it][a[it]]=1;
for(auto it1:mp[now])
mp[it][gcd(a[it],it1.first)]+=it1.second; //存下这个点连着的和目前为止的gcd的数量
dfs(it,now);
}
}
int main()
{
int n,i,x,y;
cin>>n;
for(i=1;i<=n;i++)
cin>>a[i];
for(i=1;i<n;i++)
{
cin>>x>>y;
v[x].push_back(y);
v[y].push_back(x);
}
ans=0;
mp[1][a[1]]=1;
dfs(1,0);
cout<<ans<<endl;
}