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);
}