HDU-6425 Rikka with Badminton (组合问题,快速幂)

题意:a个人没有拍子和羽毛球,b个人有拍无球,c个人有球无拍,d个人有球有拍,问不能组成游戏的有多少可能(要组成游戏即是要至少两个拍子以及1个球)
思路:我们知道要不能组成游戏即
X=0,X=1(拍子数) ;Y=0(球数).    组合下来就是  (X,Y) : (0,0)   (0,N)  (1,N)   (N,0)   ,同时还要减去重复的问题

然后每个人由参加和没有参加的状态两种所以就是 1<<n (2^n) :

理解1:

(0,N)  2^(a+c):

(1,N)    (b+d)*2^(a+c);考虑b类型和d类型的人中来了1个其余任意组合

(N,02^(a+b)

去重:在(0,N)(N,0)组成中包含了(00)的情况即所以要减去 2^a  ; (1,N)中包含了 (1,0)情况 与(N,0)中包含的情况重合所以减去 b*2^(a)

所以最后: 2^(a+c) + (b+d)*2^(a+c) + 2^(a+b) - 2^a - b*2^(a) = 2^a *(2^c + 2^c*(b+d)+2^b-1-b*2^a) = 2^a(1 + (2^b-1) + (2^c-1) *(b+d+1) + d);

理解2:

由于a参加不影响:

(1) (0,0) b,c,d都不参加 2^a

(2) (N,0) 2^(a+b) 但是和 (00)有重复所以减  -> 变成  2^(a+b)-2^a

(3) (0,N) 同理: 2^(a+c) - 2^a

(4) (1,N) : (0+1,N) 选一个b不选d :b*(2^(a+c) -2^a) ,  (0+1,1+N) 选一个d不选b :d*(2^(a+c)-2^a);

(5) (1,1) :上面不包含: 之选一个d不选c :  d*2^a

所以总式子:2^a(1 + (2^b-1) + (2^c-1) *(b+d+1) + d);

 

完整代码:

////关于位运算处理问题,虽然也能求(2^n)但是由于有取模问题(在位移中就可能出现超出mod范围而没有取模的问题) 
//int main(){
//    ios_base::sync_with_stdio(0); 
//    cin.tie(0);
//    int n;
//    cin>>n;
//    while(n--){
//        ll a,b,c,d;
//        cin>>a>>b>>c>>d;
//        ans = 0;
//        ans = (1<<a)%mod*(1+((1<<b)-1)%mod+(((1<<c)-1)%mod*(b+d+1)%mod)%mod+d)%mod;
//        printf("%lld\n",ans);
//    }    
//}
#include <iostream>
#include <cstdio>
#define mod 998244353
#define ll long long
using namespace std;
ll qpow(ll a, ll b){ int ans = 1; a = a % mod; while(b){ if(b&1)ans = (ans * a) % mod; a = (a * a) % mod; b >>= 1; } return ans%mod; } int main() { int T; ll a, b, c, d;
ll ans; scanf(
"%d",&T); while(T--) { scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
ans = qpow(2,a)%mod*(1+(qpow(2,b)-1)%mod+((qpow(2,c)-1)%mod*(b+d+1)%mod)%mod+d)%mod; printf(
"%lld\n",ans); } return 0; }

 

转载于:https://www.cnblogs.com/Tianwell/p/11272452.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值