2020 hdu多校赛 第六场 1003 Borrow
题意:
有三个整数x y z(<=1000000),每次把最大的数(如果有多个随机选)-1,再随机挑一个非最大的数+1,求这样操作直到三个数相同的期望步数。
最后15分钟想到正解,然而边界没处理好,来不及了……
我们不难发现,操作一定是经过这么一个过程(设x>=y>=z):
x y z
a a b / a+1 a b
c c c
所以,我们将整个过程分为两部分:
第一部分: x y z 到 a a b,且到a a b的上一步不是 a+1 a b-1 或 x y z 到a+1 a b-1,且上一步不是a+1 a+1 b。
第二部分 a a b到 c c c 或 a+1 a b-1到 c c c
对于第一部分的概率,我们可以利用组合数快速计算,期望步数就是x-a/x-(a+1)
对于第二部分的期望,通过列方程/看样例可以知道 a a b 到 a-1 a-1 b+2的期望步数是4,a+1 a b-1到 a a b的期望步数是2,所以我们可以O(1)求出期望步数,而他的概率承接第一部分的概率。
所以,我们只要枚举中间值a就可以快速求得答案。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<cmath> 6 #include<algorithm> 7 #define N 1000005 8 using namespace std; 9 const int p=998244353; 10 int x,y,z,T; 11 int A[10]; 12 long long jc[N],ni[N]; 13 long long ksm(long long x,long long z) 14 { 15 long long ans=1; 16 while(z) 17 { 18 if(z&1) ans=ans*x%p; 19 x=x*x%p; 20 z>>=1; 21 } 22 return ans; 23 } 24 long long get_C(int x,int y) 25 { 26 if(x<y)return 0; 27 return jc[x]*ni[y]%p*ni[x-y]%p; 28 } 29 int main() 30 { 31 jc[0]=ni[0]=1; 32 for(int i=1;i<=1000000;i++) jc[i]=jc[i-1]*i%p,ni[i]=ksm(jc[i],p-2); 33 scanf("%d",&T); 34 while(T--) 35 { 36 scanf("%d%d%d",&A[1],&A[2],&A[3]); 37 sort(A+1,A+4); 38 x=A[3],y=A[2],z=A[1]; 39 if((x+y+z)%3) 40 { 41 printf("-1\n"); 42 continue; 43 } 44 if(x==y) 45 { 46 int tmp=x+y+z; 47 tmp/=3; 48 printf("%d\n",(x-tmp)*4); 49 } 50 else if(x==y+1) 51 { 52 int tmp=x+y+z; 53 tmp/=3; 54 x--; 55 printf("%d\n",(x-tmp)*4+2); 56 } 57 else 58 { 59 long long ans=0; 60 int tmp=x+y+z; 61 tmp/=3; 62 for(int i=x-1;i>tmp&&i>=y;i--) 63 { 64 if(y+(x-i)<i)continue; 65 long long tp=ksm(ksm(2,x-i),p-2)*get_C(x-i-1,x-i-(i-y))%p; 66 // cout<<i<<' '<<tp<<endl; 67 ans+=tp*(x-i+4*(i-tmp))%p; 68 ans%=p; 69 } 70 //cout<<"Dsadasdas"<<endl; 71 for(int i=x;i>tmp&&i>=y;i--) 72 { 73 if(y+(x-i)<i-1)continue; 74 long long tp=ksm(ksm(2,x-i),p-2)*get_C(x-i,i-1-y)%p; 75 //cout<<i<<' '<<tp<<' '<<get_C(x-i,i-1-y)<<' '<<ksm(ksm(2,x-i),p-2)<<endl; 76 ans+=tp*(x-i+2+4*(i-1-tmp))%p; 77 // cout<<' '<<(x-i+2+4*(i-1-tmp))<<endl; 78 ans%=p; 79 } 80 // cout<<ans<<endl; 81 swap(y,z); 82 for(int i=x-1;i>tmp&&i>=y;i--) 83 { 84 if(y+(x-i)<i)continue; 85 long long tp=ksm(ksm(2,x-i),p-2)*get_C(x-i-1,x-i-(i-y))%p; 86 ans+=tp*(x-i+4*(i-tmp))%p; 87 ans%=p; 88 } 89 for(int i=x;i>tmp&&i>=y;i--) 90 { 91 if(y+(x-i)<i-1)continue; 92 long long tp=ksm(ksm(2,x-i),p-2)*get_C(x-i,i-1-y)%p; 93 ans+=tp*(x-i+2+4*(i-1-tmp))%p; 94 ans%=p; 95 } 96 printf("%lld\n",ans); 97 } 98 } 99 return 0; 100 }