这道题挺有意思的,记录两种方法如下:
1.推公式
“正着”算使游戏fail的条件,注意减去重复的部分,还有最后一个d(一开始没算一直错QAQ…)
附上AC代码:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
const ll MOD=998244353;
ll QuickMod(ll a,ll b)//求a^b%MOD
{
a=a%MOD;
ll ans=(ll)1;
while(b)
{
if(b&1)
ans=ans*a%MOD;
b>>=1;
a=a*a%MOD;
}
return ans%MOD;
}
ll a,b,c,d;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
cin>>a>>b>>c>>d;
ll ans=QuickMod(2,a);
ll k=(QuickMod(2,b)+(1+b+d)*(QuickMod(2,c)-1)%MOD+d)%MOD;
cout<<ans*k%MOD<<endl;
}
return 0;
}
2.容斥原理
“倒着”算使游戏sucess的条件:b+d、ab+c、2d,最后再减
b+d指至少一个b一个d,可以反着算,例如b+d:(2^b-1)*(2^d-1)*(2^c) 其余同理。
附上AC代码:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
const ll MOD=998244353;
ll QuickMod(ll a,ll b)
{
a=a%MOD;
ll ans=(ll)1;
while(b)
{
if(b&1)
ans=ans*a%MOD;
b>>=1;
a=a*a%MOD;
}
return ans%MOD;
}
ll a,b,c,d;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
cin>>a>>b>>c>>d;
ll s1=(((QuickMod(2,b)-1)%MOD)*((QuickMod(2,d)-1)%MOD)%MOD)*QuickMod(2,c)%MOD;//b+d
ll s2=(((QuickMod(2,b)-b-1)%MOD)*((QuickMod(2,c)-1)%MOD)%MOD)*QuickMod(2,d)%MOD;//2b+c
ll s3=(((QuickMod(2,d)-d-1)%MOD)*(QuickMod(2,b)%MOD)%MOD)*QuickMod(2,c)%MOD;//2d
ll s12=(((QuickMod(2,b)-b-1)%MOD)*((QuickMod(2,c)-1)%MOD)%MOD)*((QuickMod(2,d)-1)%MOD)%MOD;//2b+c+d
ll s13=(((QuickMod(2,b)-1)%MOD)*((QuickMod(2,d)-d-1)%MOD))%MOD*QuickMod(2,c)%MOD;//b+2d
ll s23=(((QuickMod(2,b)-b-1)%MOD)*((QuickMod(2,c)-1)%MOD)%MOD)*((QuickMod(2,d)-d-1)%MOD)%MOD;//2b+c+2d
ll s123=s23;
ll s=((s1+s2)%MOD+s3)%MOD-(s12+s13)%MOD;
s=QuickMod(2,b)*QuickMod(2,c)%MOD*QuickMod(2,d)%MOD-s;//最后减去
if(s<0)
s=(s+MOD)%MOD;
cout<<s*QuickMod(2,a)%MOD<<endl;//记得乘2^a
}
return 0;
}