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