1. 程式人生 > >牛客小白月賽9-11.17

牛客小白月賽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 。

待更新......