2021HDU多校1

A - Mod, Or and Everything

题意

题意很容易理解,求(n%1)|(n%2)|…|(n%(n-1))|(n%n)

思路

做这种题的时候,如果没有思路,不妨打表试试

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int ans=0;
    for(int i=1;i<=33;i++){
        ans=0;
        for(int j=1;j<=i;j++){
            ans|=i%j;
        }
        cout<<i<<' '<<ans<<endl;
    }
    return 0;
}

打表结果:
1 0
2 0
3 1
4 1
5 3
6 3
7 3
8 3
9 7
10 7
11 7
12 7
13 7
14 7
15 7
16 7
17 15
18 15
19 15
20 15
21 15
22 15
23 15
24 15
25 15
26 15
27 15
28 15
29 15
30 15
31 15
32 15
33 31

由此可以看出,答案与 2 n − 1 2^n-1 2n1有关,直接上代码

代码

/*
 * @Author: Icey_dying
 * @Date: 2021-07-21 14:46:40
 * @LastEditors: Icey_dying
 * @LastEditTime: 2021-07-28 09:44:44
 * @FilePath: \Icey_dying\competition\2021.07.21\A.cpp
 */
#include <bits/stdc++.h>
using namespace std;
int t;
long long n;
int main()
{
    cin>>t;
    while(t--){
        cin>>n;
        if(n==1) cout<<0<<endl;//进行特判
        else{
            int ans = log(n)/log(2);//log2(n)
            long long sum = pow(2,ans);
            if(sum == n) cout<<sum/2-1<<endl;//如果n是2的次幂,先除2再减
            else cout<<sum-1<<endl;
        }
    }
    return 0;
}

E - Minimum spanning tree

题意

有n-1个点,分别是2,3,…,n,现在让生成一个最小生成树,边权为lcm(a,b)。(lcm为最小公倍数)

思路

对于质数来说,它们与任何比它们小的正整数(自身除外)的最小公倍数都是该质数与另一个数的乘积,想要边权最小,只能与2相连;对于合数来说,由于 l c m ( a , b ) ≥ a 且 l c m ( a , b ) ≥ b lcm(a,b)\ge a且lcm(a,b)\ge b lcm(a,b)alcm(a,b)b,故与其相连的边权最小为其本身,那么我们可以选择和其因子相连,边权为其本身。
故边权为 { 2 × x , x 为 质 数 , x ≥ 3 x , x 为 合 数 , x ≥ 3 \begin{cases} 2\times x,x为质数,x\ge 3\\ x,x为合数,x\ge 3 \end{cases} {2×x,x,x3x,x,x3
那么,本题答案为3~n的和+从3开始的质数的和

代码

/*
 * @Author: Icey_dying
 * @Email: 825654530@qq.com
 * @Date: 2021-07-21 14:50:30
 * @Last Modified by:   Icey_dying
 * @Last Modified time: 2021-07-25 22:59:38
 * @Description: Description
 */

#include <bits/stdc++.h>
using namespace std;
const int N = 1e7+1;
int prime[N];
int b[N];
int cnt=0,max1=1e7;
int init()//素数筛
{
    memset(b,1,sizeof(b));
    b[0]=b[1]=0;
    for(int i=2;i<=max1;i++){
        if(b[i]) prime[++cnt]=i;
        for(int j=1;j<=cnt&&prime[j]*i<=max1;j++){
            b[prime[j]*i]=0;
            if(i%prime[j]==0) break;
        }
    }
}
int t,n;
int main()
{
    init();
    cin>>t;
    long long ans;
    while(t--){
        cin>>n;
        ans=0;
        for(int i=3;i<=n;i++){
            if(b[i]) ans+=i*2;
            else ans+=i;
        }
        cout<<ans<<endl;
    }
    return 0;
}

I - KD-Graph

题意

给出图的顶点和边权,现在让你把它分成k份,要求每一部分的点两两之间距离 ≤ D \le D D,两个部分之间点的距离 > D >D >D

思路

求最小值,可以用贪心,每次都解决边权最小的边,用并查集去记录分为哪几部分。

代码

/*
 * @Author: Icey_dying
 * @Date: 2021-07-28 10:09:06
 * @LastEditors: Icey_dying
 * @LastEditTime: 2021-07-28 10:32:54
 * @FilePath: \Icey_dying\competition\2021.07.21\I.cpp
 */
#include <bits/stdc++.h>
using namespace std;
struct sa{
    int x,y,w;
};
bool cmp(sa &a,sa &b)
{
    return a.w<b.w;
}
struct sa a[500005];
int fa[100005];
void init(int n)
{
    for(int i=0;i<=n;i++) fa[i]=i;
}
int find(int x)
{
    if(x==fa[x]) return x;
    return fa[x]=find(fa[x]);
}
int merge(int x,int y)
{
    x=find(x);y=find(y);
    if(x!=y){
        fa[x]=y;
        return 1;
    }
    return 0;
}
int t,n,m,k;
int main()
{
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d",&n,&m,&k);
        init(n);
        for(int i=1;i<=m;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);
        if(n==k) cout<<0<<endl;
        else{
            sort(a+1,a+1+m,cmp);
            int cnt=n,ans=-1,i=1;
            while(i<=m){
                int current_w=a[i].w;
                while(i<=m&&current_w==a[i].w){
                    int x=a[i].x;
                    int y=a[i].y;
                    if(merge(x,y)) cnt--;
                    i++;
                }
                if(cnt==k){
                    ans=current_w;
                    break;
                }
            }
            cout<<ans<<endl;
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值