传送门
给出三个数x,y,z(x,y,z <= 1e6),每次操作将最大的数减一,另外两个数等概率选择一个数加一,求出经过这样的操作使得这三个数相同的期望步数;若不能使三个数相同则输出"-1";
①考虑 “-1” 的情况,这个很简单,只要三个数的总和不是3的倍数一定不可以,特判一下就好啦;
②接下来就是简单的分类讨论:
现将这三个数从小到大排序,仍记为x,y,z;令average 为这三个数的平均数;
a,b,c为x,y,z到达average需要的步数;
第一种情况: 当y >= average时:
这时候我们将y和z看成一堆(A堆),x看成另一堆(B堆);简单想想知道,每次操作一定是从A堆中减一,那么B堆有1/2的概率加一,也有1/2的概率不加一;
记E(i)为需要 i 步变成平均数的期望步数
则E(i) = 0.5 * (E(i) + 1) + 0.5 * (E(i - 1) + 1) => E(i) = E(i - 1) + 2;
又易知:E(0) = 0, 简单计算即可得知,E(i) = 2 * i;
故第一情况时期望步数为E(a) = 2 * a;
第二种情况:当y < average时:
这时候我们需要将z看成一堆(A堆),x和y看成另一堆(B堆),这时候每次操作一定是从A堆中减一,B堆中的x和y随机加一;由于每次只能加一,则不可能使x和y同时到达average,所以一定会在某个时刻到达第一种情况;所以我们只需要枚举步数,看什么时候到达第一种情况:
对于 第 i 步到达第一种情况时(总共有2 ^ i种情况)
对于x这个数而说,它需要a步到达average,那么前i - 1步需要有a - 1个1分配给它,当第 i 步的1也分配给它时就达成了第一种情况的条件,容易得知y数还需要c - i步到达average,这时期望记为2 * (c - i);
对于y这个数而说,它需要b步到达average,那么前i - 1步需要有b - 1个1分配给它,当第 i 步的1也分配给它时就达成了第一种情况的条件,容易得知x数还需要c - i步到达average,这时期望记为2 * (c - i);
故对于第二种情况期望步数为:
∑ i = 1 c − 1 ( C i − 1 a − 1 ∗ ( i + 2 ∗ ( c − i ) ) + C i − 1 b − 1 ∗ ( i + 2 ∗ ( c − i ) ) ) 2 i \sum_{i=1}^{c-1}\frac{(C_{i-1}^{a-1}*(i + 2 * (c - i)) + C_{i-1}^{b-1} * (i + 2 * (c - i)))}{2^i} i=1∑c−12i(Ci−1a−1∗(i+2∗(c−i))+Ci−1b−1∗(i+2∗(c−i)))
之后掏出组合数模板 冲就完了!
/*******************************
* Coder : He Shuo. *
* Type : Original Work *
*******************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
#define mem(a,x) memset(a,x,sizeof(a))
#define fin freopen("input.txt", "r", stdin)
#define fout freopen("output.txt", "w", stdout)
#define IOS ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
const double PI = acos(-1.0);
const ll MAXN = 1e6 + 50;
const ll MOD = 998244353;
const ll inf = 1e18;
const ll mo = 998244353;
/** 大神的大数组合数板子 (不敢动不敢动) */
inline ll qpow(ll a, ll b){return b?((b&1)?a*qpow(a*a%MOD,b>>1)%MOD:qpow(a*a%MOD,b>>1))%MOD:1;}
inline ll qpow(ll a, ll b,ll c){return b?((b&1)?a*qpow(a*a%c,b>>1)%c:qpow(a*a%c,b>>1)) %c:1;}
ll fac[MAXN],invfac[MAXN];
void init(){
fac[0]=1;for(int i=1;i<MAXN;i++)fac[i]=fac[i-1]*i%MOD;invfac[MAXN-1]=qpow(fac[MAXN-1],MOD-2);
for(int i=MAXN-2;i>=0;i--)invfac[i]=invfac[i+1]*(i+1)%MOD;
}
ll C(int n,int m){if(m<0||m>n)return 0;return fac[n]*invfac[m]%MOD*invfac[n-m]%MOD;}
ll num[5];
ll fpow(ll a,ll b)
{
ll s = 1;
a %= mo;
while(b)
{
if(b & 1)s = s * a % mo;
a = a * a % mo;
b >>= 1;
}
return s;
}
ll inv(ll x)
{
return fpow(x,mo - 2);
}
int main()
{
init();
int q;scanf("%d",&q);
while(q --)
{
scanf("%d%d%d",&num[1],&num[2],&num[3]);
ll sum = num[1] + num[2] + num[3];
if(sum % 3)printf("-1\n");///特判-1的情况
else
{
ll average = sum / 3;
sort(num + 1,num + 1 + 3);
///x,y,z;a,b,c对应博文的含义;
ll x = num[1],y = num[2],z = num[3];
ll a = abs(x - average),b = abs(y - average),c = abs(z - average);
if(y >= average)printf("%lld\n",2 * a);///嗯,第一种情况简简单单
else///第二种情况,枚举累加简简单单~
{
ll ans = 0;
for(int i = 1;i <= c - 1;i ++)
{
ll f1 = C(i - 1,a - 1) * (i + 2 * (c - i)) % mo;
ll f2 = C(i - 1,b - 1) * (i + 2 * (c - i)) % mo;
ll res = (f1 + f2) * inv(fpow(2,i));
ans = (ans + res) % mo;
}
printf("%lld\n",ans);
}
}
}
}///写完提交,Accepted你值得拥有~