
分开考虑每一位,出现0的次数就是小于这一位前面的数的个数乘上后面位数的二次幂加上如果这一位是1就是后面位数的二次幂否则是小于等于后面的数的个数,出现1的次数减一下就行,考虑长度为len时的情况,为每一位的期望之和,只有这一位出现奇数个1时才会为1,发现是一个二项式定理(x(1的概率)+y(0的概率))的len次方减(y-x)的len次方再除以2,序列长度由n-1变为n时加了一个长度为n的前缀和。
#include <stdio.h>
#include <algorithm>
using namespace std;
#define ll long long int
const int maxn=200001,mod=998244353;
ll f[31],in1[31][2],in2[31][2],in[31][2],dp[31],t[maxn][31],len[maxn],tot[maxn];
ll l,r,ql,qr;
ll cou(ll x)
{
ll p=mod-2,temp=1;
while(p)
{
if(p%2==1)
temp=(temp*x)%mod;
x=(x*x)%mod;
p=p/2;
}
return temp%mod;
}
void init()
{
f[0]=1;
ll i;
for(i=1;i<=30;i++)
f[i]=f[i-1]*2;
ll x=l-1,pre=0,sum=0;
while(x)
{
if(x==-1)
break;
ll temp=pre+(x%2)*f[sum];
in1[sum][0]=(l-1-temp)/2;
if(x%2==1)
in1[sum][0]+=f[sum];
else
in1[sum][0]+=pre+1;
in1[sum][1]=l-in1[sum][0];
pre=pre+(x%2)*f[sum];
x=x/2;
sum++;
}
x=r,pre=0,sum=0;
while(x)
{
ll temp=pre+(x%2)*f[sum];
in2[sum][0]=(r-temp)/2;
if(x%2==1)
in2[sum][0]+=f[sum];
else
in2[sum][0]+=pre+1;
in2[sum][1]=r+1-in2[sum][0];
if(in1[sum][0]==0)
in[sum][0]=in2[sum][0]-l;//前面均为0
else
in[sum][0]=in2[sum][0]-in1[sum][0];
in[sum][1]=in2[sum][1]-in1[sum][1];
pre=pre+(x%2)*f[sum];
x=x/2;
sum++;
}
for(i=0;i<=sum-1;i++)
{
if((in[i][0]-in[i][1])%(in[i][0]+in[i][1])==0)
dp[i]=(in[i][0]-in[i][1])/(in[i][0]+in[i][1]);
else
dp[i]=((in[i][0]-in[i][1])*cou(in[i][0]+in[i][1]))%mod;
}
for(i=0;i<=sum-1;i++)
t[0][i]=1;
ll j;
for(i=0;i<=sum-1;i++)//必须卡在位数,多少都不行
{
for(j=1;j<=qr;j++)
t[j][i]=(t[j-1][i]*dp[i])%mod;
}
ll temp=cou(2);//不存在不能整除的除法,预处理出来2的逆元
for(i=1;i<=qr;i++)
{
for(j=0;j<=sum-1;j++)
len[i]=(len[i]+((((1-t[i][j]+mod)%mod)*temp)%mod*f[j])%mod)%mod;
tot[i]=(tot[i-1]+len[i])%mod;
}
}
int main()
{
scanf("%lld%lld%lld%lld",&l,&r,&ql,&qr);
init();
ll i,ans=0;
for(i=1;i<=ql;i++)
ans=(ans+((ql-i+1)*len[i])%mod)%mod;
printf("%lld\n",ans%mod);
for(i=ql+1;i<=qr;i++)
{
ans=(ans+tot[i])%mod;
printf("%lld\n",ans%mod);
}
return 0;
}
浙公网安备 33010602011771号