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; }
2018航電多校練習第9場-快速冪