2018航电多校练习第9场-快速幂
Rikka with Badminton
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 53 Accepted Submission(s): 44
Problem Description
In the last semester, Rikka joined the badminton club.
There are n students in the badminton club, some of them have rackets,
and some of them have balls. Formally, there are a students have neither
rackets nor balls, bstudents have only rackets, c students have only
balls, and d students have both rackets and balls. (a+b+c+d=n)
This week, the club is going to organize students to play badminton.
Each student can choose to take part in or not freely. So there
are 2n possible registration status.
To play badminton, there must be at least two students who have rackets
and at least one students who have balls. So if there aren't enough
balls or rackets, the activity will fail.
Now, Rikka wants to calculate the number of the status among
all 2n possible registration status which will make the activity fail.
Input
The first line contains a single number t(1≤t≤103), the number of testcases.
For each testcase, the first line contains four integers a,b,c,d(0≤a,b,c,d≤107,a+b+c+d≥1).
Output
For each testcase, output a single line with a single integer, the answer modulo 998244353.
Sample Input
3
1 1 1 1
2 2 2 2
3 4 5 6
Sample Output
12
84
2904
题意:
给你a,b,c,d四种人的人数:分别代表什么都没有,一个拍,一个球,一个球一个拍
问你有多少种可能连一个球两个拍都没有
a不需要讨论
当d取1时,b必须为0,c随便取:(fun(2,a)%maxx * fun(2,c)%maxx) *d %maxx;
当d取0时,b取1或0,c随便取:(fun(2,a)%maxx * (b+1)%maxx)*fun(2,c)%maxx;
当d取0时,b取0或1以外的数,c必须为0:(fun(2,a)%maxx * (fun(2,b)-b-1+maxx)%maxx)%maxx;
三种情况相加,输出时还要取模
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 #define maxx 998244353 5 6 ll fun(ll a,ll b){ 7 ll r = 1; 8 while(b){ 9 if(b&1){ 10 r = (r*a)%maxx; 11 } 12 a = (a*a)%maxx; 13 b>>=1; 14 } 15 return r; 16 } 17 int main(){ 18 int T; 19 while(scanf("%d",&T)!=EOF){ 20 while(T--){ 21 ll a,b,c,d; 22 scanf("%lld%lld%lld%lld",&a,&b,&c,&d); 23 ll ans = 0; 24 ans += (fun(2,a)%maxx * fun(2,c)%maxx) *d %maxx; 25 ans += (fun(2,a)%maxx * (b+1)%maxx)*fun(2,c)%maxx; 26 ans += (fun(2,a)%maxx * (fun(2,b)-b-1+maxx)%maxx)%maxx; 27 printf("%lld\n",ans%maxx); 28 } 29 } 30 return 0; 31 }
乘法取模:
(a*b)%mod = ((a%mod) * (b*mod)) % mod
除法取模:
费马小定理:若p是质数,且a、p互质,那么a^(p-1) mod p = 1。
现在,我们要求a/c mod p,通过一系列神奇的转化,那万恶的除法就会神奇地消失...
a / c mod p
= a / c mod p * 1
= a / c mod p * c^(p-1) mod p
= a * c^(p-2) mod p
快速幂:
乘法在计算机中处理的时间并不是这么快的,也要拆分为加法来做的。所以快速乘法会更快的计算a*b的结果,而且a*b%mod可能还没取模就已经爆long long,但快速乘法却不会。快速幂也是同样的道理。
实现的原理都是基于按照二进制位一步一步乘来避免重复的操作,利用前面的中间结果,从而实现快速的目的。
对于乘数b来说,势必可以拆成2进制,比如110101。有一些位为0,有一些位为1。根据乘法分配律:a*b=a*(b1+b2+b3+……)
那么对于a*53 = a*110101(二进制)=
a*(100000+10000+100+1)=a*(100000*1+10000*1+1000*0+100*1+10*0+1*1)。
那么设立一个ans=0用于保存答案,每一位让a*=2,在根据b的对应为1看是不是加上此时的a,即可完成快速运算。
long long q_mul( long long a, long long b, long long mod ) //快速计算 (a*b) % mod { long long ans = 0; // 初始化 while(b) //根据b的每一位看加不加当前a { if(b & 1) //如果当前位为1 { b--; ans =(ans+ a)%mod; //ans+=a } b >>= 1; //b向前移位 a = (a + a) % mod; //更新a } return ans; }
long long q_pow( long long a, long long b, long long mod ) //快速计算 (a^b) % mod { long long ans = 1; // 初始化 while(b) //根据b的每一位看乘不乘当前a { if(b & 1) //如果当前位为1 { ans = (ans*a)%mod //ans*=a } b >>= 1; //b向前移位 a = (a*a)%mod; //更新a } return ans; }