1. 程式人生 > >牛客小白月賽9 - A、B、C、H

牛客小白月賽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);
}