文章目录
A Ares, Toilet Ares 点击查看 1050/5067 通过
题意:
这题的题意就是厕所启发灵感哈哈哈
49-33
思路:
这里就是a+Πpi,pi就是成功概率相乘,但这里要分数取模+求逆元作除法
♡ \heartsuit ♡分数取模!
我们如果要求这个式子-------
1
a
\frac{1}{a}
a1
m
o
d
mod
mod
p
p
p
我们可以根据费马小定理
所以就可以把 1 a \frac{1}{a} a1 m o d mod mod p p p转化成 a p − 2 a^{p-2} ap−2 m o d mod mod p p p
如果分子不是1,那么就 m ∗ a − 1 m*a^{-1} m∗a−1 m o d mod mod p p p = = = ( m (m (m m o d mod mod p ) p) p) ∗ * ∗ ( a − 1 (a^{-1} (a−1 m o d mod mod p ) p) p) m o d mod mod p p p
其中m为素数,如果m过大,可以用快速求正整数幂
然后他的代码有点像快速幂,可以给你们对比一下
分数取模代码
long long fast_mod(long long a,long long b) {
long long r = 1;
a %= mod;
while (b) {
if (b & 1) r = (r*a) % mod;
a = (a*a) % mod;
b >>= 1;
}
return r;
}
快速幂代码
long long fastPower(long long base, long long power) {
long long result = 1;
while (power > 0) {
if (power & 1) //此处等价于if(power%2==1)
result = result * base % 1000;
power >>= 1;//此处等价于power=power/2
base = (base * base) % 1000;
}
return result;
}
取模的运算规则
模运算与基本四则运算有些相似,但是除法例外。
其规则如下:
(a + b) % p = (a % p + b % p) % p
(a - b) % p = (a % p - b % p) % p
(a * b) % p = (a % p * b % p) % p
a ^ b % p = ((a % p)^b) % p
结合律:
((a+b) % p + c) % p = (a + (b+c) % p) % p
((ab) % p * c)% p = (a * (bc) % p) % p
交换律:
(a + b) % p = (b+a) % p
(a * b) % p = (b * a) % p
分配律:
(a+b) % p = ( a % p + b % p ) % p
((a +b)% p * c) % p = ((a * c) % p + (b * c) % p) % p
逆元
当求解公式:(a/b)%m 时,因b可能会过大,会出现爆精度的情况,所以需变除法为乘法:
设c是b的逆元,则有b*c≡1(mod m);
则 ( a / b ) (a/b) (a/b) m o d mod mod m m m = = = ( a / b ) (a/b) (a/b) ∗ 1 *1 ∗1 m o d mod mod m m m = = = ( a / b ) ∗ b (a/b)*b (a/b)∗b ∗ * ∗ c c c m o d mod mod m m m= a a a ∗ * ∗ c c c ( m o d (mod (mod m ) m) m);
即a/b的模等于a*(b的逆元)的模;
const int mod = 1000000009;
long long quickpow(long long a, long long b) {
if (b < 0) return 0;
long long ret = 1;
a %= mod;
while(b) {
if (b & 1) ret = (ret * a) % mod;
b >>= 1;
a = (a * a) % mod;
}
return ret;
}
long long inv(long long a) {
return quickpow(a, mod - 2);
}
最后一个知识点:负数取模变正数
(a % b + b) % b
代码1:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL mod = 4933;
LL pows(LL a, LL x, LL p)
{
if(x==0)return 1;
LL t = pows(a, x>>1,p);
if(x%2==0)return t*t%p;
return t*t%p*a%p;
}
LL inv(LL x, LL p)
{
return pows(x,p-2,p);
}
int main()
{
LL n,m,k,a,l;
cin>>n>>m>>k>>a>>l;
LL ans = 1;
for(int i=1; i <= k; i++)
{
int x, y, z;
cin>>x>>y>>z;
if(x!=0)//这是这一道题的唯一坑点就是如果x=0
(ans *= (1-y*inv(z,mod)%mod+mod)%mod)%=mod;
}
ans = (ans+a)%mod;//(ans+a%mod+mod)%mod;
cout<<ans<<endl;
return 0;
}
代码2:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
const ll mod=4933;
ll ny(ll a,ll k,ll mod){
ll res=1;
while(k){
if(k&1) res=(ll)res*a%mod;
a=(ll)a*a%mod;
k/=2;
}
return res;
}
int main()
{
int flag=0;
ll n,m,k,a,l;
cin>>n>>m>>k>>a>>l;
ll ans=1;
// if(n==a){
// cout<<a%mod<<endl;
// return 0;
// }
for(int i=1;i<=k;i++){
ll x,y,z;
cin>>x>>y>>z;
if(x!=0){
if(y==z){
flag=1;
}else{
ans=(ans*((z-y)*ny(z,mod-2,mod)%mod))%mod;
}
}
}
if(flag){
cout<<a%mod<<endl;
}else{
cout<<(ans+a)%mod<<endl;
}
return 0;
}
wa了几次就是因为没有每一步都mod,这种取模的题不是第一次在牛客中出现,就再碰到类似的题的话,自己写的完全对也很难,所以,多看多思考!
♡ \heartsuit ♡ D OR 点击查看 937/4152 通过
输入
4
7 5 5
7 9 5
输出
2
与运算规则
0&0=0;0&1=0;1&0=0;1&1=1
即:两个同时为1,结果为1,否则为0
或运算规则
0|0=0; 0|1=1; 1|0=1; 1|1=1;
即 :参加运算的两个对象,一个为1,其值为1。
异或运算规则
0^0=0; 0^1=1; 1^0=1; 1^1=0;
即:参加运算的两个对象,如果两个位为“异”(值不同),则该位结果为1,否则为0。
题意:
给了你两个数组,一个数组
b
i
=
a
i
−
1
∣
a
i
b_i=a_{i-1}|a_i
bi=ai−1∣ai,一个数组是
c
i
=
a
i
−
1
+
a
i
c_i=a_{i-1}+a_i
ci=ai−1+ai,然后让你求数组a
思路:
要知道一个重要性质!
a
+
b
a+b
a+b
=
=
=
a
a
a &
b
b
b
+
a
∣
b
+a|b
+a∣b
=
=
==
==》
d
i
=
(
a
i
d_i=(a_i
di=(ai &
a
i
−
1
)
=
c
i
−
b
i
a_i-1)=c_i-b_i
ai−1)=ci−bi
所以这个时候我们每一位分开考虑,即考虑
a
1
a_1
a1的几种可能取值即可
时间复杂度O(
n
∗
l
o
g
a
n*loga
n∗loga)
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e6;
int d[N],b[N],c[N];//数据范围在0~2的31次方,所以不会爆long long
int main()
{
int n,ans=1;
cin>>n;
for(int i=2;i<=n;i++)
scanf("%d",&b[i]);
for(int i=2;i<=n;i++)
{
scanf("%d",&c[i]);
d[i]=c[i]-b[i];
}
for(int i=0;i<31;i++)
//因为他最多是31位,所以开始枚举他的每一位,分开考虑
{
int x=1,y=1;//表示&、|的可行性
for(int j=2;j<=n;j++)//枚举每一位的可能情况,要好好想想哦!我想了好久的!
{
int w1=(b[j]>>i)&1,w2=(d[j]>>i)&1;
int tx=0,ty=0;
if(w1==1&&w2==1)ty=y;//&=1,|=1,那么就只有都为1的时候
if(w1==1&&w2==0)tx=y,ty=x;//&=0,|=1,那么即可为0,又可以为1
if(w1==0&&w2==0)tx=x;//&=0,|=0,那么就只有都为0的情况
x=tx,y=ty;
}
ans*=(x+y);
}
cout<<ans<<endl;
}
我感觉这里核心代码很巧妙哦!记住这个用法!
♡ \heartsuit ♡E Rise of Shadows 点击查看 1678/1988 通过
1
2020
no
#include <bits/stdc++.h>
using namespace std;
int main(){
int t;
cin>>t;
while(t--){
int a;
cin>>a;
printf("no\n");
}
return 0;
}
这个就是要即是闰年又是质数的年,当然不存在拉,如果有人按死办法算,由于数据范围在1e7左右,那么就不能用素数筛,只能一一看
int is_prime(int x){
if(x==1)return false;
if(x==2)return true;
for(int i =2; i*i <= x; i++){
if(x%i==0)return false;
}
return true;
}
♡ \heartsuit ♡K Yet Another Problem About Pi 点击查看 1268/9615 未通过
输入
2
5 5
1.5 1.5
输出
4
8
题意:
每隔w一个纬线,每隔d一个经线,你只能走最多
π
\pi
πm,请问你最多能都经过多少个格子?
思路:
沿着边走+2
沿着斜线走+3
显然,一开始的时候在区域的格点最优,这样子起始就是4!
数据范围很小,可以暴力枚举
令
a
=
m
i
n
(
w
,
d
)
a=min(w,d)
a=min(w,d),
b
=
(
w
∗
w
+
d
∗
d
)
b=\sqrt{(w*w+d*d)}
b=(w∗w+d∗d),求解满足ax+by<=
π
\pi
π 时
2
x
+
3
y
2x+3y
2x+3y的最大值
为了保证精度, π \pi π用这个 a c o s ( − 1 ) acos(-1) acos(−1)来表示
方法一:暴力枚举
#include<iostream>
#include<cstring>
#include<algorithm>
#include<math.h>
using namespace std;
const double pi=acos(-1);
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
//这个是为让cin和cout的运行效率跟scanf和printf差不多
int t;
cin>>t;
while(t--)
{
double w,d;
cin>>w>>d;
double a=min(w,d);
double b=sqrt(w*w+d*d);
int ans=0;
for(int x=0;x<=100&&a*x<=pi;x++)//横着走x步
ans=max(ans,2*x+3*(int)((pi-a*x)/b)+4);//要想下取整
for(int y=0;y<=100&&b*y<=pi;y++)
ans=max(ans,2*(int)((pi-b*y)/a)+3*y+4);
cout<<ans<<endl;
}
return 0;
}
方法二:战略思维
这个名字哈哈哈哈,就是考虑性价比
#include<iostream>
#include<cstring>
#include<algorithm>
#include<math.h>
using namespace std;
typedef long long ll;
const double pi=acos(-1);
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
//这个是为让cin和cout的运行效率跟scanf和printf差不多
int t;
cin>>t;
while(t--)
{
double w,d;
cin>>w>>d;
double a=min(w,d);
double b=sqrt(w*w+d*d);
int ans=0;
double xa=a/2,xb=b/3;//这里是看这两个谁的性价比高,得到的结果是平均每一个格子所要的步长
if(xa<xb)//走直线
{
int tans=(ll)(pi/a);
ans+=tans*2;
if(pi-(tans-1)*a>b)ans++;//如果去掉一条直线,可以走斜线的话,就+1
}
else
{
int tans=(long long)(pi/b);
ans+=tans*3;
if(pi-tans*b>a)ans+=2;//就是最后虽然走不了斜线了,如果能走直线
else if(pi-(tans-1)*b>a)ans+=1;//如果去掉一条斜边可以走两个直线
}
cout<<ans<<endl;
}
return 0;
}