牛客小白月赛9-11.17

A.签到(除数取模转化为逆元快速幂)

链接:https://ac.nowcoder.com/acm/contest/275/A
来源:牛客网
 

你在一栋楼房下面,楼房一共有n层,第i层每秒有pi的概率会扔下一个东西并砸到你
求第一秒内你被砸到的概率

输入描述:

第一行一个整数n
之后有n行,第i+1行有两个整数ai,bi,表示

输出描述:

设答案为,你只需要找到一个最小的非负整数T,使得
输出这个T就行了

示例1

输入

复制

2
1 2
1 2

输出

复制

750000006

说明

一共只有如下状态:

1. 第一层和第二层都扔了下来

2. 第一层扔了下来

3. 第二层扔了下来

4. 第一层和第二层都没有扔下来

以上四种都是等概率发生的

除了第四种情况外,都会被砸到

因此被砸到的概率是 3/4,这个值在模1e9+7意义下就是750000006

备注:

数据范围
0 ≤ n ≤ 105
1 ≤ ai ≤ bi ≤ 105

思路说明:这个的话,除法的取模,是要求出逆元的,(A/B)%mod=A*B^(MOD-2);求出这个就差不多了。。。。

代码:

#include<bits/stdc++.h>
using namespace std;
using LL=long long;
const int M=1e5+5;
const int mo=1e9+7;
LL qpow(LL a,LL b)
{
    LL res=1;
    while(b)
    {
        if(b&1)
            res=res*a%mo;
        b>>=1;
        a=a*a%mo;
    }
    return res;
}
 
int main()
{
    int n;
    LL fz1=1,fz2=1,fm=1,a,b;
    scanf("%d",&n);
    while(n--)
    {
        scanf("%lld%lld",&a,&b);
        fz1=fz1*b%mo;
        fz2=fz2*(b-a)%mo;
        fm=fm*b%mo;
    }
    LL res=(fz1-fz2+mo)%mo*qpow(fm,mo-2)%mo;
    printf("%lld\n",res);
    return 0;
}

B.法法(思维)

链接:https://ac.nowcoder.com/acm/contest/275/B
来源:牛客网
 

题目描述

设 A 是一个 的排列,其中第 i 项为 Ai



换句话说:



的全排列的 f 的和

答案对 2 取模

输入描述:

第一行输入一个整数 T,表示数据组数
之后 T 行,第 i+1 行有一个整数 ni,表示第 i 次询问

输出描述:

一共 T 行,第 i 行有 1 个整数,表示第 i 次询问的答案

示例1

输入

复制

1
3

输出

复制

0

说明

 
 

备注:

 

数据范围

1 ≤ n ≤ 1018
1 ≤ T ≤ 10

思路:这个的话,不难想象后面的数值,因为只要涉及到全排列,后面的(A)!,A只要满足大于2就%2=0了,而且即便是有奇数做底数的,那样只要上面的数大于2个,那么一定有偶数中排列,奇数+奇数=偶数,这样就出现了基本上全是偶数了,但是少数还是要特殊判断一下。

代码:

#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#define ll long long
using namespace std;

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
       ll n;
        cin>>n;
        if(n<=2)
            cout<<1<<endl;
        else
            cout<<0<<endl;
    }
    return 0;
}

C.红球进黑洞(线段树)

链接:https://ac.nowcoder.com/acm/contest/275/C
来源:牛客网
 

题目描述

在心理疏导室中有一种奇特的疏导工具,叫做红球。红球被提前分为了许多正方形小方格。
每当有人来找ATB做心理疏导时,ATB就会让他去先玩红球,然后通过红球小格方的高度来判断一个人的压力程度的高低
具体地讲,ATB会让该人对于一个序列执行以下操作
1. 区间求和,即输入l,r,输出
2. 区间异或,即输入l,r,k,对于l ≤ i ≤ r,将xi变为
可是ATB天天算计那么多答案,已经对这份工作产生了厌烦,所以请你帮帮他,对于一组给定的数据,输出对应的答案
ATB会将你感谢到爆

输入描述:

第一行两个整数n和m,表示数列长度和询问次数
第二行有n个整数,表示这个数列的初始数值
接下来有m行,形如 1 l r 或者 2 l r k
分别表示查询
或者对于l ≤ i ≤ r,将xi变为

输出描述:

对于每一个查询操作,输出查询的结果并换行

示例1

输入

复制

10 10
8 5 8 9 3 9 8 3 3 6 
2 1 4 1
1 2 6 
2 9 10 8
1 1 7 
2 4 7 8
2 8 8 6
2 2 3 0
1 1 2 
2 9 10 4
1 2 3 

输出

复制

33
50
13
13

备注:

1. 数据范围
对于的数据,保证 n, m, k≤ 10
对于另外的数据,保证 n, m ≤ 50000, k ∈ {0, 1}

对于全部的数据,保证 1 ≤ n,m ≤ 105, 0≤ ai,k ≤ 105

2. 说明

表示

思路参考自:https://blog.csdn.net/u013852115/article/details/84193227

主要问题是处理Xor操作。可以用一个二维的线段树维护,第二维存储每一位中1的个数。然后区间更新。如果k的当前位为1,那么将tree[v][i]中的0变为1,1变为0,即1的个数为(R-L+1)-tree[v][i]。复杂度为O(nlogn*40)。

代码:

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100005
#define ll long long
int n,m;
ll tree[4*MAXN][40],laz[4*MAXN],que;
void build(int v,int L,int R)
{
    if(L==R)
    {
        ll d;
        scanf("%lld",&d);
        for(int i=0;d;i++)
        {
            tree[v][i]=d&1;
            d>>=1;
        }
    }
    else
    {
        int mid=(L+R)/2;
        build(v*2,L,mid);
        build(v*2+1,mid+1,R);
        for(int i=0; i<40; i++)
            tree[v][i]=tree[v*2][i]+tree[v*2+1][i];
    }
}
 
void pushdown(int L,int R,int v)
{
    laz[v*2]^=laz[v];
    laz[v*2+1]^=laz[v];
    int d=laz[v];
    int mid=(L+R)/2;
    for(int i=0; i<20 && d; i++,d>>=1)
    {
        if(d&1)
        {
            tree[v*2][i]=(mid-L+1)-tree[v*2][i];
            tree[v*2+1][i]=(R-mid)-tree[v*2+1][i];
        }
    }
    laz[v]=0;
}
void updata(int v,int L,int R,int ql,int qr,ll q)
{
    if(ql<=L && R<=qr)
    {
        ll d=q;
        for(int i=0; i<20 && d; i++,d>>=1)
        {
            if(d&1) tree[v][i]=(R-L+1)-tree[v][i];
        }
        laz[v]^=q;
        return;
    }
    if(laz[v]) pushdown(L,R,v);
    int mid=(L+R)/2;
    if(ql<=mid) updata(v*2,L,mid,ql,qr,q);
    if(qr>mid) updata(v*2+1,mid+1,R,ql,qr,q);
    for(int i=0; i<40; i++)
        tree[v][i]=tree[v*2][i]+tree[v*2+1][i];
}
void query(int v,int L,int R,int ql,int qr)
{
    if(ql<=L && R<=qr)
    {
        for(int i=0; i<40; i++)
            que+=(1LL<<i)*tree[v][i];
        return;
    }
    if(laz[v]) pushdown(L,R,v);
    int mid=(L+R)/2;
    if(ql<=mid) query(v*2,L,mid,ql,qr);
    if(qr>mid) query(v*2+1,mid+1,R,ql,qr);
}
int main()
{
    scanf("%d%d",&n,&m);
    memset(tree,0,sizeof tree);
    memset(laz,0,sizeof laz);
    build(1,1,n);
 
    for(int i=0; i<m; i++)
    {
        int op,l,r;
        ll d;
        scanf("%d",&op);
        if(op==2)
        {
            scanf("%d%d%lld",&l,&r,&d);
            updata(1,1,n,l,r,d);
        }
        else
        {
            scanf("%d%d",&l,&r);
            que=0;
            query(1,1,n,l,r);
            printf("%lld\n",que);
        }
    }
    return 0;
}

E.换个角度思考(暴力)

链接:https://ac.nowcoder.com/acm/contest/275/E
来源:牛客网
 

题目描述

给定一个序列,有多次询问,每次查询区间里小于等于某个数的元素的个数
即对于询问 (l,r,x),你需要输出 的值
其中 [exp] 是一个函数,它返回 1 当且仅当 exp 成立,其中 exp 表示某个表达式

输入描述:

第一行两个整数n,m
第二行n个整数表示序列a的元素,序列下标从1开始标号,保证1 ≤ ai ≤ 105
之后有m行,每行三个整数(l,r,k),保证1 ≤ l ≤ r ≤ n,且1 ≤ k ≤ 105

输出描述:

对于每一个询问,输出一个整数表示答案后回车

示例1

输入

复制

5 1
1 2 3 4 5
1 5 3

输出

复制

3

备注:

数据范围
1 ≤ n ≤ 105
1 ≤ m ≤ 105

思路:乍一看树状数组像是,发现暴力过了 

代码:

#include<stdio.h>
const int maxn = 1e5 + 5;
int a[maxn];
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    for(int i = 0; i < n; i++)
        scanf("%d", a + i);
    while(m--)
    {
        int l, r, k, ans = 0;
        scanf("%d%d%d", &l, &r, &k);
        for(int i = l-1; i < r; i++)
            ans += a[i] <= k;
        printf("%d\n", ans);
    }
}

H.论如何给出一道水题

链接:https://ac.nowcoder.com/acm/contest/275/H
来源:牛客网
 

题目描述

给定 n,求一对整数 (i,j),在满足 1 ≤ i ≤ j ≤ n 且 的前提下,要求最大化 i+j 的值

输入描述:

第一行一个整数 n

输出描述:

一行一个整数表示答案

示例1

输入

复制

2

输出

复制

3

备注:

数据范围
1 ≤ n ≤ 1018

思路:很水,加一个N=1时候的判断就行了,因为相邻的数一定是互质的,

代码:

#include<iostream>
#include<cstring>
#include<string>
#define ll long long
using namespace std;

int main()
{
    ll n;
    cin>>n;
    if(n==1)
        cout<<2<<endl;
    else
    {
        cout<<n+n-1<<endl;
    }
    return 0;
}

G.简单

链接:https://ac.nowcoder.com/acm/contest/275/G
来源:牛客网
 

题目描述

给定一个森林,每个点都有一定概率会消失,一条 的边存在的条件是,u 存在且 v 存在。
有若干次询问,每次给定 [l,r],然后把下标不在 [l,r] 的点都删掉后,问剩余点和所有边构成的图的连通块个数的期望。
注意每次删除的意思是只在当前这个询问的时候删除,对于其它询问互相独立

输入描述:

第一行三个整数 n,m,q,分别表示点的个数和边的个数和询问次数。
之后 n 行,第 i+1 行有两个整数 ai,bi,表示第 i 个点存在的概率是  。
之后 m 行,每行有两个整数 u,v,表示存在一条连接 u 和 v 的边,保证无重边无自环。
之后 q 行,每行两个整数 [l,r],表示一次询问。

输出描述:

对于每一次询问,输出一行一个整数表示答案,输出对 109+7 取模。

示例1

输入

复制

2 1 1
1 1
1 1
1 2
1 2

输出

复制

1

说明

一共就俩点,都一定存在,所以连接它们的这条边一定存在,所以这俩点构成的图的连通块个数一定是 1

示例2

输入

复制

5 4 5
1 1
1 1
2 3
1 2
1 1
3 4
4 5
3 2
3 1
1 2
1 3
2 5
1 2
1 3

输出

复制

2
333333337
666666673
2
333333337

示例3

输入

复制

10 9 10
2922 17409
11774 17075
4095 19350
5213 7090
21155 26703
9167 16671
257 1197
201 308
13874 27985
12034 32560
1 6
1 9
6 5
6 4
1 10
4 3
4 2
10 7
6 8
2 3
3 9
1 3
2 2
2 6
3 5
2 2
3 5
5 8
4 4

输出

复制

613369885
419229271
380731593
15695462
543771231
562072744
15695462
562072744
891100707
526234137

说明

(以下内容与本题无关)

这个样例,无疑是善良的出题人无私的馈赠。

大量精心构造的 n ≤ 100,m ≤ 200 的测试数据,涵盖了测试点中所有出现性质的组合。

你可以利用这个测试点,对自己的程序进行全面的检查。

足量的数据组数、不大的数据范围和多种多样的数据类型,能让程序中的错误无处遁形。

出题人相信,这个美妙的样例,可以给拼搏于 AC 这道题的逐梦之路上的你,提供一个有力的援助。

备注:

对于  的数据,保证 n = 10 。
对于另外  的数据,保证 q=1 。
对于所有  的数据,保证 1 ≤ n,q ≤ 105,0 ≤ m < n,1 ≤ ai ≤ bi ≤ 105 。

待更新......

 

猜你喜欢

转载自blog.csdn.net/wentong_Xu/article/details/84194598