CodeChef-RNDRATIO Mysterious Ratio 题解
CodeChef-RNDRATIO Mysterious Ratio
题意简述:
对每个 ,随机选择一个数 ,满足 ,求 的期望。
, 。
Example Input:
2 1 1 3 2 2 4 5 5 Example Output:
1 15
好久没做毒瘤式子题,推错好几次...
不过后面用到的乘法差分还是比较新颖,记录一下吧。
答案显然是这个式子——
前面的 是常数可以先抛开,后面就暴算吧。(等式右边 后有少许说明)
所以最终的式子便是
其中
显然 是个积性函数,故可以用线性筛预处理出其前 项,只需用到如下的性质
其实如果所有 都相等的话就可以直接上杜教筛 / min25筛之类的黑科技把复杂度优化到 了,但这道题很不套路的不相等,所以我们需要找到方法对所有 快速计算后面的 。
正解巧妙的使用了乘法差分。首先 对所有 都整除分块一次得到区间,然后在 上做乘法差分,每个分块区间乘上贡献 。最后计算的时候扫一遍就能拿到每个 对应的 的值了。
注意对 的特殊处理。
CodeChef上跑不过,懒得卡常了。
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<ctime> #include<cstdlib> #include<queue> #include<algorithm> #include<map> #include<set> #include<vector> using namespace std; typedef long long ll; typedef double db; ll Rd(){ ll ans=0;bool fh=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-') fh=1; c=getchar();} while(c>='0'&&c<='9') ans=ans*10+c-'0',c=getchar(); if(fh) ans=-ans; return ans; } ll CD(ll a,ll b){return (a-1)/b+1;} //CeilDiv const ll MOD=998244353,INF=1E18; #define _ %MOD ll PMod(ll x){ if(x>=MOD) return x-MOD; else if(x<0) return x+MOD; else return x; } ll QPow(ll x,ll up){ PMod(x _);ll ans=1; while(up){ if(up%2==0) x=x*x _,up/=2; else ans=ans*x _,up--; } return ans; } ll Inv(ll x){return QPow(x,MOD-2);} const ll INV2=Inv(2); const ll MXN=1E5+5; ll P[MXN],pN; bool notP[MXN]; ll f[MXN];//\sum_{d|n} \mu(d) d void LinearSieve(ll n){ notP[1]=1;for(ll i=2;i<=n;i++) notP[i]=0; pN=0;f[1]=1; for(ll i=2;i<=n;i++){ if(!notP[i]){ P[++pN]=i; f[i]=PMod(1-i); } for(ll j=1;j<=pN&&i*P[j]<=n;j++){ notP[i*P[j]]=1; if(i%P[j]==0){ f[i*P[j]]=f[i]; break; } f[i*P[j]]=f[i]*f[P[j]]_; } } } ll S(ll n){return n*(n+1)_*INV2 _;} ll N,MI; ll L[MXN],R[MXN]; /*namespace Normal{ void Solve(){ ll Ans=0; for(ll t=1;t<=MI;t++){ ll pdt=1;for(ll i=1;i<=N;i++) pdt=pdt*PMod(S(R[i]/t)-S(CD(L[i],t)-1))_; Ans=(Ans+QPow(t,N-1)*f[t]_*pdt)_; } ll pdt=1;for(ll i=1;i<=N;i++) pdt=pdt*Inv(R[i]-L[i]+1)_; Ans=Ans*pdt _; printf("%lld\n",Ans); } }*/ namespace Lunatic{ ll diff[MXN],zero[MXN]; ll bl[MXN],br[MXN],blN,brN; void PutDiff(){ for(ll k=1;k<=MI;k++) diff[k]=1,zero[k]=0; for(ll i=1;i<=N;i++){ brN=0;for(ll t=1;t<=R[i];t=R[i]/(R[i]/t)+1) br[++brN]=R[i]/(R[i]/t); br[++brN]=MI; blN=0;for(ll t=MI;t>=1;t=CD(L[i],CD(L[i],t))-1) bl[++blN]=t; for(ll j=blN,k=1,st=1,ed;st<=MI;st=ed+1){ if(bl[j]<br[k]||k>brN) ed=bl[j--]; else ed=br[k++]; ll t=ed; ll val=PMod(S(R[i]/t)-S(CD(L[i],t)-1)); if(val){ diff[st]=diff[st]*val _; diff[ed+1]=diff[ed+1]*Inv(val)_; }else{ zero[st]++; zero[ed+1]--; } } } } void Solve(){ PutDiff(); ll Ans=0; ll pdt=1,zn=0; for(ll t=1;t<=MI;t++){ zn+=zero[t];pdt=pdt*diff[t]_; if(!zn) Ans=(Ans+QPow(t,N-1)*f[t]_*pdt)_; } pdt=1;for(ll i=1;i<=N;i++) pdt=pdt*Inv(R[i]-L[i]+1)_; Ans=Ans*pdt _; printf("%lld\n",Ans); } } int main(){ LinearSieve(MXN-1); ll T=Rd();while(T--){ N=Rd(); MI=INF; for(ll i=1;i<=N;i++){ L[i]=Rd();R[i]=Rd(); MI=min(MI,R[i]); } //Normal::Solve(); Lunatic::Solve(); } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现