牛客小白月赛9 - A、B、C、H

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

思路:

概率就是1-没被砸着的概率

然后用费马小定理求逆元

注意一定要多%%,ans=(ans*a%mod*mod_pow(b,mod-2)%mod)%mod;

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<cmath>
#include<set>
#define ll long long
using namespace std;
const int mod=1000000007;

ll mod_pow(ll a,ll b){
    ll res=1;
    a%=mod;
    while(b){
        if(b&1)res=(res*a)%mod;
        b>>=1;
        a=(a*a)%mod;
    }
    return res%mod;
}

int main(){
     ll a,b;
     int n;
     scanf("%d",&n);
     ll ans=1;
     for(int i=1;i<=n;i++){
        scanf("%lld%lld",&a,&b);
        a=b-a;
        ans=(ans*a%mod*mod_pow(b,mod-2))%mod;
     }
     printf("%lld\n",(1-ans+mod)%mod);
}

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

思路:

这里只需要考虑但n=1,2就行了

因为我们可发现,全排列A1是奇数,那么A1的几次方也都是奇数

若n>3我们发现以任意元素开头的全排列的个数是偶数,偶数个奇数相加也是偶数

但是n=1,2时是奇数

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<cmath>
#include<set>
#define ll long long
using namespace std;
const int mod=1000000007;
 
int main(){
     int t;
     ll n;
     scanf("%d",&t);
     while(t--){
        scanf("%lld",&n);
        if(n==1||n==2)printf("1\n");
        else printf("0\n");
     }
}

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. 说明

表示

思路 :

我刚开始看成k只能取1,0了,我是智障吗???

1 ≤ n,m ≤ 1e5, 0≤ ai,k ≤ 1e5,那么转换成二进制后估计一下不会超过21位

那么我们用aa[rt][i]数组来表示根为rt的值的第i位上有多少个1

具体看代码

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<cmath>
#include<set>

using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

const int mod=1000000007;
const int N=1e5+5;
int aa[N<<2][35],ff[N<<2];

void push_up(int rt){
    for(int i=0;i<21;i++){//第i位是1的个数
        aa[rt][i]=aa[rt<<1][i]+aa[rt<<1|1][i];
    }
}

void push_down(int l,int r,int rt){
    if(ff[rt]){
        ff[rt<<1]^=ff[rt];
        ff[rt<<1|1]^=ff[rt];
        int m=(l+r)>>1;
        for(int i=0;i<21;i++){
            if((ff[rt]>>i)&1){
                aa[rt<<1][i]=m-l+1-aa[rt<<1][i];
                aa[rt<<1|1][i]=r-m-aa[rt<<1|1][i];
            }
        }
        ff[rt]=0;
    }
    return ;
}

void build(int l,int r,int rt){
    if(l==r){
        int tmp;
        scanf("%d",&tmp);
        for(int i=0;i<21;i++){
            if((tmp>>i)&1)aa[rt][i]=1;
            else aa[rt][i]=0;
        }
        return ;//一定要记得加这一句,别问我怎么知道的qwq
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    push_up(rt);
}

void update(int L,int R,int C,int l,int r,int rt){
    if(L<=l&&R>=r){
        ff[rt]^=C;
        for(int i=0;i<21;i++){
            if((C>>i)&1){//该位置为1的话会产生影响
                aa[rt][i]=r-l+1-aa[rt][i];
                //该位为1,那么异或后0变1,1变0
                //1的个数是这个区间的总数r-l+1减去原来1的个数,aa[rt][i]
            }
        }
        return ;
    }
    int m=(l+r)>>1;
    push_down(l,r,rt);
    if(L<=m)update(L,R,C,lson);
    if(R>m)update(L,R,C,rson);
    push_up(rt);
}

ll query(int L,int R,int l,int r,int rt){
    if(L<=l&&R>=r){
        ll ans=0;
        for(int i=0;i<21;i++){
            ans+=((ll)aa[rt][i]<<i);
        }
        return ans;
    }
    int m=(l+r)>>1;
    push_down(l,r,rt);
    ll ans=0;
    if(L<=m)ans+=query(L,R,lson);
    if(R>m)ans+=query(L,R,rson);
    return ans;
}

int main(){
     int n,m,flag,l,r,k;
     scanf("%d%d",&n,&m);
     memset(ff,0,sizeof(ff));
     build(1,n,1);
     while(m--){
        scanf("%d",&flag);
        if(flag==1){
            scanf("%d%d",&l,&r);
            printf("%lld\n",query(l,r,1,n,1));
        }
        else {
            scanf("%d%d%d",&l,&r,&k);
            update(l,r,k,1,n,1);
        }
     }
}

H - 论如何出一道水题

题目描述

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

输入描述:

第一行一个整数 n

输出描述:

一行一个整数表示答案

示例1

输入

复制

2

输出

复制

3

备注:

数据范围
1 ≤ n ≤ 1018

思路:

相邻的两个数一定互质:

设两个数a,a+1,若不互质,那么公约数是m,m*x=a   m*y=a+1

那么:m*x=m*y-1即m*(y-x)=1

因为,m,x,y都不为1,所以不成立,综上:相邻的两个数一定互质

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<cmath>
#include<set>
#define ll long long
using namespace std;
const int mod=1000000007;

int main(){
     ll n;
     scanf("%lld",&n);
     if(n==1)printf("2\n");
     else printf("%lld\n",2*n-1);
}

猜你喜欢

转载自blog.csdn.net/m0_37579232/article/details/84235802