Link
先考虑(m=2^k)的情况。
首先我们可以设计一种可行的策略:连续抛(k)次硬币得到(2^k)种结果,而每个数(i)对应其中(a_i)种。
不难发现每个数对应的一些结果是可以合并的,即扔不到(k)就能确定是哪个数。
可以证明最优的合并方案的结果就是(frac{a_i}m)在(2)进制下的各个(1)位。
对于每个(a_i),设(frac{a_i}m=sumlimits_{xin S(a_i)}frac1{2^x}),那么结果就是(sumlimits_{i=1}^nsumlimits_{xin S(a_i)}frac x{2^x})。
然后考虑(m
e2^k)的情况。
简单推理可以发现,此时有一些结果不会对应任何一个数,也就是说(S(x))可能变成了一个无限集,但是(m=2^k)时的结论依旧适用。
记(f(frac xm)=sumlimits_{iin S(x)}frac i{2^i}),那么答案就是(sumlimits_{i=1}^nf(frac{a_i}m))。
但是直接求(f)看上去不太现实,我们发现(f(2x-lfloor2x
floor)=2f(x)-2x),不难发现它会成环。
成环之后我们就可以推出环中某个(f(x))继而推出环中所有(f(x))了。
#include<stack>
#include<cstdio>
const int N=10000007,P=998244353;
int m,inv,cnt,a[N],pw[N],vis[N],is[N],f[N];std::stack<int>stk;
int read(){int x;scanf("%d",&x);return x;}
int inc(int a,int b){return a+=b-P,a+(a>>31&P);}
int mul(int a,int b){return 1ll*a*b%P;}
int pow(int a,int k){int r=1;for(;k;k>>=1,a=mul(a,a))if(k&1)r=mul(a,r);return r;}
int next(int x){return x+x>=m? x+x-m:x+x;}
void solve(int x)
{
int a=1,b=mul(x,inv),y=next(x);
while(y^x) b=inc(b,mul(mul(pw[a],y),inv)),++a,y=next(y);
f[x]=mul(b,pow(P+1-pw[a],P-2)),is[x]=1;
}
int main()
{
int n=read(),ans=0;
for(int i=1;i<=n;++i) m+=a[i]=read();
inv=pow(m,P-2),pw[0]=1;
for(int i=1,x=P-P/2;i<=m;++i) pw[i]=mul(pw[i-1],x);
for(int i=0;i<m;++i)
if(!vis[i])
{
for(int x=i;!vis[x];x=next(x)) vis[x]=1,stk.push(x);
if(!is[next(stk.top())]) solve(stk.top()),stk.pop();
for(int x;!stk.empty();) x=stk.top(),stk.pop(),f[x]=inc(mul(f[next(x)],pw[1]),mul(x,inv)),is[x]=1;
}
for(int i=1;i<=n;++i) ans=inc(ans,f[a[i]]);
printf("%d",ans);
}