牛客练习赛8

A.约数个数的和

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
给个n,求1到n的所有数的约数个数的和~

输入描述:
第一行一个正整数n
输出描述:
输出一个整数,表示答案
示例1
输入
3
输出
5
说明
样例解释:
1有1个约数1
2有2个约数1,2
3有2个约数1,3
备注:
n <= 100000000

题解:结论题。相当于枚举那个约数,查一下有多少个数有那个约数

#include<cstdio>

int main()
{
    int n,ans = 0;
    scanf("%d",&n);
    for (int i=1; i<=n/2; ++i) ans += (n/i);

    printf("%d",ans+n - n/2);

    return 0;
}

D.加边的无向图

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
给你一个 n 个点,m 条边的无向图,求至少要在这个的基础上加多少条无向边使得任意两个点可达~

输入描述:
第一行两个正整数 n 和 m 。
接下来的m行中,每行两个正整数 i 、 j ,表示点i与点j之间有一条无向道路。
输出描述:
输出一个整数,表示答案
示例1
输入
4 2
1 2
3 4
输出
1
备注:
对于100%的数据,有n,m<=100000。

题解:dfs,bfs,并查集三选一,随便搞,只要搜连通块的个数就行啦。
答案就是连通块的个数-1.

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
const int maxn  = 200000+5;
int pre [maxn];
bool flag[maxn];

void init ()
{
    for (int i = 1; i <= maxn; i++)
        pre[i]= i, flag[i] = false; 
} 
int find (int x)
{
    return pre[x] == x ? x : pre[x]=find (pre[x]);
}

void join(int a, int b)
{
    int fx = find(a);
    int fy = find(b);
    if (fx != fy) {
            pre[fx] = fy;
        }
}
int main ()
{


        int n,m; scanf("%d %d",&n,&m);
        init ();
        for (int i = 1; i <= m; i++){
            int a,b; scanf("%d %d",&a,&b);
            join(a, b);
            flag[a] =true;
            flag[b] = true;
        }
        int cnt = 0;
        for (int i = 1; i <= n; i++){
            if (flag[i] == false) cnt ++;
            if (flag[i] == true && pre[i] == i) cnt++;
        }
        printf("%d\n",cnt - 1);
        return 0;   
}

集合中的质数

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
给出一个集合和一个数m。

集合里面有n个质数。

请你求出从 1 到 m 的所有数中,至少能被集合中的一个数整除的数的个数。

输入描述:
第一行两个正整数 n 和 m 。
第二行n个正整数,分别为集合中的质数。
输出描述:
输出一个整数,表示符合要求的正整数的个数。
示例1
输入
3 37
5 7 13
输出
13
备注:
对于100%的数据,有n<=20,m为有符号64位正整数,集合内质数<=1000000000

题解:容斥,然后直接求就可以了,因为所有数都互质。
一直在考虑会不会出题人故意卡long long什么的,果然是不存在的。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,m;
ll a[30];
ll ans = 0;
void dfs(int i, ll lcm, int cc)
{
    if (lcm > m) return;
    lcm = a[i]/__gcd(a[i],lcm) *lcm;
    if (cc & 1) ans += m / lcm;
    else ans -= m / lcm;

    for (int j = i + 1; j < n; j++){
        dfs(j,lcm,cc+1);
    }
}
int main ()
{
    scanf("%lld %lld",&n,&m);
    for (int i = 0; i < n; i++) scanf("%lld",&a[i]);

    for (int i = 0; i < n; i++) dfs(i,a[i],1);

    printf("%lld\n",ans);
}

储物点的距离

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述

一个数轴,每一个储物点会有一些东西,同时它们之间存在距离。
每次给个区间[l,r],查询把这个区间内所有储物点的东西运到另外一个储物点的代价是多少?
比如储物点i有x个东西,要运到储物点j,代价为x * dist( i , j )
dist就是储物点间的距离。

输入描述:
第一行两个数表示n,m

第二行n-1个数,第i个数表示第i个储物点与第i+1个储物点的距离ai

第三行n个数,表示每个储物点的东西个数bi

之后m行每行三个数x l r

表示查询要把区间[l,r]储物点的物品全部运到储物点x的花费
每次查询独立
输出描述:
对于每个询问输出一个数表示答案
答案对1000000007取模

题解: 第一眼以为线段树?? 仔细看??不需要更新啊。
维护前缀和后缀和半天,被-1卡了好久╮(╯▽╰)╭。
然而样例过了 case通过率 0% ?? 被mod卡死了。。哪里都不能少mod系列。

#include<bits/stdc++.h>
using namespace std;
#define MAX 210000
#define mod 1000000007
typedef long long ll;
ll a[MAX], b[MAX];
ll dis_l[MAX],cost_l[MAX];
ll dis_r[MAX],cost_r[MAX];
ll cnt[MAX];
ll ql(int x,int l, int r)
{
    ll res = (cost_l[r] - cost_l[l-1]) % mod; // l-r 运到1

    ll dis = (cnt[r] - cnt[l-1]) * dis_l[x] % mod; // l-r 运回 x
//    printf("ql_res = %lld, dis = %lld\n",res,dis);
    return (res - dis) % mod;
}
ll qr(int x,int l, int r)
{
    ll res = (cost_r[l] - cost_r[r+1]) % mod;
    ll dis = (cnt[r] - cnt[l-1]) * dis_r[x] % mod;
  //  printf("qr_res = %lld, dis = %lld\n",res,dis);
    return (res - dis) % mod;
}
int main ()
{
    int n,m; scanf("%d %d",&n,&m);
    for (int i = 1; i < n; i++) scanf("%d",&a[i]);
    for (int i = 1; i <= n; i++) scanf("%d",&b[i]);

    for (int i = 2; i <= n; i++){    // 前缀和
        dis_l[i] = (dis_l[i-1] + a[i-1]) % mod;
        cost_l[i] = (cost_l[i-1] + dis_l[i]*b[i]) % mod;
    }

    for (int i = n-1; i >= 1; i--){   // 后缀和
        dis_r[i] = (dis_r[i+1] + a[i]) % mod;
        cost_r[i] = (cost_r[i+1] + dis_r[i]*b[i]) % mod;
    }

    for (int i = 1; i <= n; i++){
        cnt[i] = (cnt[i-1] + b[i]) % mod;
    }

    for(int i = 1; i <= m ; i++){
        ll ans = 0;
        int l,r,x; scanf("%d %d %d",&x,&l,&r);
        if (x <= l) ans = ql(x,l,r);
        else if (x >= r) ans = qr(x,l,r);
        else ans = (ql(x,x+1,r) + qr(x,l,x-1)) % mod;
     //   printf("11  = %d %d\n",ql(x,x+1,r) , qr(x,l,x-1));
        printf("%lld\n",(ans+mod)% mod);
    }
    return 0;
}

如果有什么不懂欢迎留言。

如果我们志同道合 QQ 747117793

如有不足敬请批评指正!这里是yyy_3y!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值