【牛客练习赛8】A D E

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
分析: 枚举因子,看1-n中有几个数是有这个因子的。
代码

//package FirstTime;
import java.util.*;
import java.math.*;
import java.text.DecimalFormat;

public class Main{
    static final int MAXN = 10000+11;
    static final int MAXM = 100000+11;
    static final int inf = 0x3f3f3f3f;

    public static void main(String[] agrs){
        Scanner cin = new Scanner(System.in);
        int n;
        while(cin.hasNext()){
            n=cin.nextInt();
            long ans=0;int i;
            for(  i=1;i*i<=n;i++){
                ans+=n/i;
            }
            ans+=(n-i+1);
            System.out.println(ans);
        }


    }
}

B 储物点的距离
时间限制: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
输入

5 5
2 3 4 5
1 2 3 4 5
1 1 5
3 1 5
2 3 3
3 3 3
1 5 5
输出

125
72
9
0
70
备注:
对于100%的数据n,m <= 200000 , 0 <= ai,bi <= 2000000000
分析: 打出前缀表,好吧,我代码bug调半天还没有调出来(看别人正确代码,打的表一样的啊,但是好像最后查询处 计算的方法不太一样,可能错这里了)还要补作业 ,晚点再贴吧,QAQ 。

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扫一遍。

#include
using namespace std;

const int MAXN = 1e5+11;
const int MAXM = 1e6;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;

bool vis[MAXN+2];
vector<int>ve[MAXN+2];
int n,m;
int ans;
void init(){
    for(int i=0;i<=n;i++) ve[i].clear();
    memset(vis,0,sizeof(vis));
}
void dfs(int now,int pre){
    vis[now]=1;
    for(int i=0;iint v=ve[now][i];
        if(vis[v]||v==pre) continue;
        dfs(v,now);
    }
}
int main(){

    scanf("%d%d",&n,&m);
    init();
    while(m--){
        int a,b;scanf("%d%d",&a,&b);
        ve[a].push_back(b);
        ve[b].push_back(a);
    }
    ans=0;
    for(int i=1;i<=n;i++){
        if(!vis[i]) {
             ans++;
             dfs(i,-1);
        }
    }
    printf("%d\n",ans-1);
    return 0;
}

E 集合中的质数
时间限制: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

分析:容斥裸题,这里用的状态压缩枚举所有状态。
有一点就是这个LCM的时候可能会爆LL,就改了一点,当时想着要是还是爆LL ,就要上java了,但是这样就可以过了。

#include
using namespace std;
#define LL long long

const int MAXN = 30;
const int MAXM = 1e6;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;

LL a[MAXN];
int main(){

    LL n,m;
    while(scanf("%lld%lld",&m,&n)!=EOF){
        for(int i=0;iscanf("%lld",&a[i]);
        LL ans=0;
        for(int i=1;i<(1<//
            int cnt=0;  LL LCM = 1;  int flag=0;
            for(int j=0;jif(1&(i>>j)) {
                    if(LCM>n) { // 可以直接逃过
                        flag=1;
                        break;
                    }
                    cnt++;
                    LCM= LCM*a[j];
                 }
             }
             if(flag) continue;
             if(cnt&1) ans+=n/LCM;
             else ans-=n/LCM;
         }
         printf("%lld\n",ans);
     }
}

你可能感兴趣的:(状态压缩,容斥原理)