[UESTC 1419]条头日今の面试(一)

吐槽:这种标题也是没谁了

题目描述
省府弟子乐天潭在条头日今的笔试中遇到了四道题,其中第一题是:
已知 n 和 t,构造一棵 n 个结点的树,使得边权和最大。
结点的编号为 1 到 n,对于边权 w(u,v) = GCD(u,v) &t。

乐天潭很强势,一眼就知道了解法,但计算量实在过大,没办法只好偷偷掏出手机请你帮他写一个程序算出答案。
输入
第一行,两个整数 n (1 <= n <= 3000),t (1 <= t <= 10^9+7)。

输出
输出一行,一个整数,表示答案。

输入样例
3 3

输出样例
2

提示

w(u,v)表示边(u,v)的边权,GCD(u,v)表示u和v的最小公约数,&表示二进制按位与

样例有三种构造方法:
方法一:将1和2,2和3连边,GCD(1,2)&3 + GCD(2,3)&3 = 2
方法二:将1和2,1和3连边,GCD(1,2)&3 + GCD(1,3)&3 = 2
方法三:将1和3,2和3连边,GCD(1,3)&3 + GCD(2,3)&3 = 2

题解:最大生成树,边权就是gcd(u,v)&t,由于边数太多,请使用坑爹的prim算法。。。

#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#define pa pair<long long , int >
#define LiangJiaJun main
#define INF 199912270000LL
using namespace std;
int n;long long t;
long long gcd(long long x,long long y){
    return y==0?x:gcd(y,x%y);
}
priority_queue<pa,vector<pa>,greater<pa> >q;
int mp[3004][3004];
long long mcs[3004];
bool vis[3004];
long long prim(){
    for(int i=0;i<=n;i++)mcs[i]=INF;
    long long ans=0;
    q.push(make_pair(0,1));
    mcs[1]=0;
    while(!q.empty()){
        int x=q.top().second;q.pop();
        if(vis[x])continue;
        ans+=mcs[x];vis[x]=1;
        for(int i=1;i<=n;i++){
            if(mcs[i]>mp[x][i]&&x!=i){
                mcs[i]=mp[x][i];
                q.push(make_pair(mcs[i],i));
            }
        }
    }
    return -ans;
}
int LiangJiaJun(){
    scanf("%d%I64d",&n,&t);
    for(int i=1;i<=n;i++){
        mp[i][i]=0;
        for(int j=1;j<i;j++){
            mp[j][i]=mp[i][j]=-(gcd((long long)i,(long long)j)&t);
        }
    }
    printf("%d\n",prim());
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值