牛客练习赛 8 (1~n约数和)(前缀和好题)(加边得连通图)(容斥原理)

A
题目描述

给个n,求1n的所有数的约数个数的和~

输入描述:

第一行一个正整数n

输出描述:

输出一个整数,表示答案
示例1

输入

3

输出

5

说明

样例解释:
1有1个约数1
2有2个约数1,2
3有2个约数1,3

备注:

n <= 100000000

#include

int deal(int n)
{
    int ans=0;
    for(int i=1;i<=n;i++)
        ans+=n/i;
    return ans;
}
int main()
{
    int n;
    //freopen("in.txt","r",stdin);
    while(scanf("%d",&n)!=EOF)
        printf("%d\n",deal(n));
    return 0;
}


B

题目描述


 一个数轴,每一个储物点会有一些东西,同时它们之间存在距离。
每次给个区间[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


思路:

计算所有点到点1的距离以及前缀和,然后根据关系计算得到答案即可

另一种思路:计算前面所有点到 i 的权值和,但是不知道为什么一直错,找不到原因了


#include
#include
#include
using namespace std;

#define MAXN 200005
#define LL long long
#define mod 1000000007

int n,m;
LL a[MAXN],b[MAXN],s[MAXN];

void init(){
    for(int i=2;i<=n;i++)
            scanf("%lld",&a[i]),a[i]=(a[i]+a[i-1])%mod;
    for(int i=1;i<=n;i++)
        scanf("%lld",&b[i]),s[i]=(s[i-1]+a[i]*b[i])%mod,b[i]=(b[i]+b[i-1])%mod;
}

LL get_left(int l,int r,int x){
    return a[x]*(b[r]-b[l-1])-(s[r]-s[l-1]);
}
LL get_right(int l,int r,int x){
    return s[r]-s[l-1]-a[x]*(b[r]-b[l-1]);
}

int main()
{
    //freopen("in.txt","r",stdin);
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        while(m--)
        {
            int x,l,r;
            scanf("%d%d%d",&x,&l,&r);
            LL ans=0;
            if(x>=r)      ans=get_left(l,r,x);
            else if(x<=l) ans=get_right(l,r,x);
            else ans=get_left(l,x,x)+get_right(x,r,x);
            printf("%lld\n",(ans%mod+mod)%mod);
        }
    }
    return 0;
}





D

题目描述

给你一个 个点,条边的无向图,求至少要在这个的基础上加多少条无向边使得任意两个点可达

输入描述:

第一行两个正整数 n 和 m 。
接下来的m行中,每行两个正整数 i 、 j ,表示点i与点j之间有一条无向道路。

输出描述:

输出一个整数,表示答案
示例1

输入

4 2
1 2
3 4

输出

1

备注:

对于100%的数据,有n,m<=100000。


利用并查理求得连通块有ans个,则输出 ans-1即可

也可以利用dfs,bfs求得

#include
#include
#include
using namespace std;

#define MAXN 100005
int father[MAXN],visit[MAXN];
int find_it(int x){
    int tempx=x,t;
    while(tempx!=father[tempx])
        tempx=father[tempx];
    while(father[x]!=x){
        t=father[x];
        father[x]=tempx;
        x=t;
    }
    return tempx;
}
void unite(int num1,int num2){
    int tx=find_it(num1);
    int ty=find_it(num2);
    if(tx!=ty)
        father[tx]=ty;
}

int main()
{
    int n,m,a,b;
    //freopen("in.txt","r",stdin);
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=0;i<=n;i++)
            father[i]=i;
        for(int i=0;i


E

题目描述

给出一个集合和一个数m

集合里面有n个质数。

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

输入描述:

第一行两个正整数 n 和 m 。
第二行n个正整数,分别为集合中的质数。

输出描述:

输出一个整数,表示符合要求的正整数的个数。
示例1

输入

3 37
5 7 13

输出

13

备注:

对于100%的数据,有n<=20,m为有符号64位正整数,集合内质数<=1000000000

容斥原理处理一下

注意这里n个数都是质数,我们可以直接两个数相乘得到最大公约数,如果不能保证是质数,则要求得最大公约数

因为18/6 + 18/9  - 18/lcm(6,9)答案才是正确的

#include
#include
#include
using namespace std;

#define LL long long
LL a[100];
LL n,m,ans;

LL gcd(LL a,LL b)
{
    return b?gcd(b,a%b):a;
}
LL lcm(LL a,LL b)
{
    return a*b/gcd(a,b);
}

void dfs(int now,LL num,int sym)
{
    if(num)  ans+=m/num*sym;
    for(int i=now+1;i<=n;i++)
        dfs(i,lcm(num,a[i]),-1*sym);
}

int main()
{
    //freopen("in.txt","r",stdin);
    while(scanf("%lld%lld",&n,&m)!=EOF)
    {
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        ans=0;
        for(int i=1;i<=n;i++)
            dfs(i,a[i],1);
        printf("%lld\n",ans);
    }
    return 0;
}




你可能感兴趣的:(组合数学,数,论,acm,数据结构)