XXR1T2题解
XXR1T2 题解
题面
思路
首先我们有引理:对于一件事情 X,我们每一次做 X 的成功概率是 P,如果成功则不继续做,不成功则继续做,这样做成功的期望次数是 1P,
证明:设做成功的期望次数为 num,则有如下式子:
num=1+P×0+(1−P)×num
(1 代表当前做了 1 次;P×0 代表成功了则不继续做;(1−P)×num 代表没成功则继续做,期望次数为 num)
移项得 num=1P。
那么开始解释这题。
0 只猫的猫舍直接判掉就好了。
每个猫舍独立,所以只要会一个就会全部,假设当前猫舍有 n(n⩾1) 只猫。
首先 n 只猫中取到 1 个没有被抓过的猫的概率为 nn=1,期望次数为 11=1。
n 只猫中抓到剩下 n−1 只没有被抓过的猫中的一只的概率 P2 为 n−1n,期望次数 num2 为 1P2=nn−1。
……
最后 n 只猫抓到剩下唯一一只没有被抓过的猫的概率 Pn 为 1n,期望次数 numn 为 1Pn=n。
所以这个猫舍的答案为 n∑i=1numi=n∑i=1ni=n×n∑i=11i。
所以只要线性求逆元后加一个前缀和,最后就可以得出每一个猫舍的答案,加起来输出就好了。
于是就可以得到一个 80 分的做法:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll __int128
using namespace std;
const int MN=1e6+5;
const ll mod=1145141999;
ll n,a[MN],inv[MN],sum[MN],ans;
void write(ll n){if(n<0){putchar('-');write(-n);return;}if(n>9)write(n/10);putchar(n%10+'0');}
ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
int main(){
freopen("cat.in","r",stdin);
freopen("cat.out","w",stdout);
n=read();
for(int i=1; i<=n; i++) a[i]=read();
sum[1]=inv[1]=1;for(int i=2; i<MN; i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod,sum[i]=(sum[i-1]+inv[i])%mod;
for(int i=1; i<=n; i++) ans=(ans+a[i]*sum[a[i]]%mod)%mod;
write(ans);
return 0;
}//250216
接下来发现时间有 2s,所以可以有两只 log,于是把加减乘除都用位运算来实现了!
加法
就是在二进制下加,先计算没有进位的 a⨁b,然后将有进位的左移一位,以便后面加,而至于为啥代码中是 (a^b)&b
,因为前面 a 已经异或过 b 了。
ll add(ll a, ll b){while(b!=0)a^=b,b=((a^b)&b)<<1;return a%mod;}
减法
减法可以通过加上负数的补码来实现。计算补码可以通过取反加一的方式来实现。
ll jian(ll a, ll b){return add(a,add(~b,1));}
乘法
正常龟速乘,就是和快速幂同样原理。
ll mul(ll a, ll b){
ll res=0;
if(a<b)swap(a,b);
while(b){
if(b&1)res=add(res,a);
a<<=1;b>>=1;
}
return res%mod;
}
除法
除法可以通过减法和位移来实现。从被除数中减去除数的倍数,直到结果小于除数为止。每次减去的倍数可以通过左移除数来得到。
ll chu(ll a, ll b){
ll res=0;
while(a>=b){
ll tmp=b,x=1;
while(a>=(tmp<<1)){tmp<<=1;x<<=1;}
a=jian(a,tmp);res=add(res,x);
}
return res;
}
于是,改一下代码就出来了,注意常数。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
using namespace std;
const int MN=1000005;
const ll mod=1145141999;
ll n,a[MN],inv[MN],sum[MN],ans,maxn;
ll add(ll a, ll b){while(b!=0)a^=b,b=((a^b)&b)<<1;return a%mod;}
ll mul(ll a, ll b){ll res=0;if(a<b)swap(a,b);while(b){if(b&1)res=add(res,a);a<<=1;b>>=1;}return res%mod;}
ll jian(ll a, ll b){return add(a,add(~b,1));}
ll chu(ll a, ll b){ll res=0;while(a>=b){ll tmp=b,x=1;while(a>=(tmp<<1)){tmp<<=1;x<<=1;}a=jian(a,tmp);res=add(res,x);}return res;}
int main(){
freopen("cat.in","r",stdin);
freopen("cat.out","w",stdout);
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1; i<=n; i=(i&1?add(i,1):i^1)) cin>>a[i],maxn=max(maxn,a[i]);
sum[1]=inv[1]=1;for(int i=2; i<=maxn; i=(i&1?add(i,1):i^1)) inv[i]=mul(jian(mod,chu(mod,i)),inv[mod%i]),sum[i]=add(sum[jian(i,1)],inv[i]);
for(int i=1; i<=n; i=(i&1?add(i,1):i^1)) ans=add(ans,mul(a[i],sum[a[i]]));
cout<<ans;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!