HDU6829 | 2020杭电多校1003 Borrow

传送门

简化题意

给出三个数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=1c12i(Ci1a1(i+2(ci))+Ci1b1(i+2(ci)))
之后掏出组合数模板 冲就完了!

代码实现

/*******************************
*   Coder : He Shuo.           *
*   Type : Original Work       *
*******************************/

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<queue>
#include<vector>
#include<deque>
#include<stdlib.h>
#include<set>
#include<bitset>
#include<map>
#include<unordered_map>
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你值得拥有~

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值