题意

初始有一个空数组\(a\),接下来每次操作会这么做:

  1. 在\([1,n]\)中选择一个数,将其拼接在数组\(a\)后。
  2. 计算数组\(a\)的\(\gcd\)。
  3. 如果结果是\(1\),退出。
  4. 否则,回到步骤1.

试问数组\(a\)长度的期望,答案对\(1e^9+7\)取模。

题解

莫反解法

考虑dp。

设\(dp[x]\)为当前数组的\(\gcd\)为\(x\)时的期望长度,那么答案便是

\[ans=\sum_{i=1}^n\frac{1+dp[i]}{n}=1+\sum_{i=1}^n\frac{dp[i]}{n}
\]

由\(dp[x]\)的意义,考虑对其因子进行转移,即

\[dp[x]=1+\frac{1}{n}\sum_{i=1}^ndp[\gcd(i,x)]
\]

然而\(O(n^2)\)的时间复杂度必定是超时的,于是考虑优化。

对于\(\gcd(i,x)\),它必定是\(x\)的因子,于是可以优化成

\[dp[x]=1+\frac{1}{n}\sum_{d|x}dp[d]*h(x,d)
\]

其中\(h(x,d)\)表示\([1,n]\)中与\(x\)的\(\gcd\)为\(d\)的个数,即

\[h(x)=\sum_{i=1}^n[\gcd(x,i)==d]
\]

对于优化后的\(dp[x]\)的表达式,由于左右两边可能都含有\(dp[x]\),于是我们把\(dp[x]\)单独分离出来

\[n*dp[x]=n+\sum_{d|x,d\neq x}dp[d]*h(x,d)+dp[x]*h(x,x)
\]

其中

\[h(x,x)=\lfloor \frac{n}{x} \rfloor
\]

通过移项,变形得

\[(n-\lfloor\frac{n}{x}\rfloor)dp[x]=n+\sum_{d|x,d\neq x}dp[d]*h(x,d)
\]

接下来再分析\(h(x,d)\):

\[h(x,d)=\sum_{i=1}^n [\gcd(x,i)==d]=\sum_{i=1}^{\lfloor \frac{n}{d}\rfloor}[\gcd(\frac{x}{d}, i)==1]=\sum_{i=1}^{\lfloor \frac{n}{d}\rfloor}\sum_{t|\frac{x}{d}, t|i}\mu(t)
\]

变换求和顺序得

\[h(x,d)=\sum_{t|\frac{x}{d}}\sum_{i=1}^{{\lfloor \frac{n}{d}\rfloor}}[t|i]\mu(t)=\sum_{t|\frac{x}{d}}\lfloor\frac{n}{dt}\rfloor \mu(t)
\]

带入原式

\[dp[x]=\frac{n+\sum_{d|x,d\neq x}(dp[d]*\sum_{t|\frac{x}{d}}\lfloor\frac{n}{dt}\rfloor \mu(t))}{n-\lfloor\frac{n}{x}\rfloor}
\]

AC代码

#include <bits/stdc++.h>
#define IO ios::sync_with_stdio(NULL)
#define sc(z) scanf("%d", &(z))
#define _ff(i, a, b) for (ll i = a; i <= b; ++i)
#define _rr(i, a, b) for (ll i = b; i >= a; --i)
#define _f(i, a, b) for (ll i = a; i < b; ++i)
#define _r(i, a, b) for (ll i = b - 1; i >= a; --i)
#define pii pair<int, int>
#define mkp make_pair
#define endl "\n"
using namespace std;
typedef long long ll; const int N = 1e6 + 5;
const ll mod = 1e9 + 7; ll dp[N]; vector<ll> mind[N];
bool prime[N];
ll primes[N], cnt, mu[N], inv[N]; void precompute() {
mu[1] = 1, cnt = 0;
_ff(i, 2, N) {
if (!prime[i]) {
primes[cnt++] = i;
mu[i] = -1;
}
_f(j, 0, cnt) {
if (primes[j] * i > N) break;
prime[i * primes[j]] = 1;
if (i % primes[j]) {
mu[i * primes[j]] = -mu[i];
} else {
mu[i * primes[j]] = 0;
break;
}
}
}
_ff(i, 1, N) {
mu[i] = (mu[i] + mod) % mod;
for (int j = i + i; j < N; j += i) mind[j].push_back(i);
}
inv[1] = 1;
_ff(i, 2, N) inv[i] = (mod - mod / i) * inv[mod % i] % mod;
} int main() {
ll n; cin >> n;
precompute();
_ff(x, 2, n) {
dp[x] = n;
for (ll d : mind[x]) {
//由于之前筛因子的时候并没有把自身筛进去,于是这里要单独计算t=x/d的情况
ll s = n / x * mu[x / d] % mod;
for (ll t : mind[x / d]) {
s = (s + n / d / t * mu[t]) % mod;
}
dp[x] = (dp[x] + s * dp[d]) % mod;
}
dp[x] = dp[x] * inv[n - n / x] % mod;
}
ll ans = 0;
_ff(i, 1, n) ans = (ans + dp[i]) % mod;
ans = ans * inv[n] % mod;
cout << ans + 1 % mod;
return 0;
}

无穷级数解法

根据期望的定义,我们可以得到

\[ans=\sum_{i=1}^niP(i)
\]

如何计算\(P(i)\)呢?我们设\(P(E)\)为事件\(E\)发生的概率,设当前长度为\(len\),那么我们可以计算\(len\)的期望\(P(len>x)\):

\[E(len)=1+\sum_{x=1}^{\infty}P(len>x)
\]

注意到\(len>x\)就意味着所有前\(x\)个数是不互质的,那么\(P(len>x)\)就可以表示为

\[P(len>x)=\sum_{i=2}^nP(\gcd(a_1,a_2,...,a_x)=i)
\]

我们令\(ans_i=\sum_{x=1}^{\infty}P(\gcd(a_1,a_2,...,a_x)=i)\),那么最终答案就为

\[ans=1+\sum_{i=2}^nans_i
\]

那么如何计算\(ans_i\)呢?我们可以根据容斥原理,先计算前\(x\)个数都是x的倍数的概率,再减去前\(x\)个数的\(\gcd\)是\(i\)的倍数的概率,即

\[ans_i=\sum_{x=2}^{\infty}P(gcd(a_1,a_2,...,a_x)=i)=\sum_{x=2}^{\infty}P(前x个数都能整除i)-\sum_{j=2}^{\lfloor\frac{n}{i}\rfloor}ans_{j*i}
\]

我们很容易知道,在\([1,n]\)中取一个\(i\)的倍数的概率为\(\frac{\lfloor \frac{n}{i}\rfloor}{n}\),那么原式就为

\[ans_i=\sum_{x=1}^{\infty}(\frac{\lfloor \frac{n}{i}\rfloor}{n})^x-\sum_{j=2}^{\lfloor\frac{n}{i}\rfloor}ans_{j*i}
\]

很容易知道,级数\(\sum_{x=1}^{\infty}(\frac{\lfloor \frac{n}{i}\rfloor}{n})^x\)是收敛的,收敛为\(\frac{1}{1-\frac{\lfloor \frac{n}{i}\rfloor}{n}}-1\)。

AC代码

#include <bits/stdc++.h>
#define IO ios::sync_with_stdio(NULL)
#define sc(z) scanf("%d", &(z))
#define _ff(i, a, b) for (int i = a; i <= b; ++i)
#define _rr(i, a, b) for (int i = b; i >= a; --i)
#define _f(i, a, b) for (int i = a; i < b; ++i)
#define _r(i, a, b) for (int i = b - 1; i >= a; --i)
#define pii pair<int, int>
#define mp make_pair
using namespace std;
typedef long long ll; const int N = 1e5 + 5;
const ll mod = 1e9 + 7;
ll ans[N]; ll qpow(ll a, ll b) {
ll res = 1;
while (b) {
if (b & 1) res = (res * a) % mod;
a = (a * a) % mod;
b >>= 1;
}
return res;
} ll inv(ll x) { return qpow(x, mod - 2); } int main() {
ll n; cin >> n;
ll dans = 1;
_rr(i, 2, n) {
ans[i] = (inv((1 - n / i * inv(n) + mod) % mod) - 1 + mod) % mod;
for (ll j = i + i; j <= n; j += i) {
ans[i] = (ans[i] - ans[j] + mod) % mod;
}
dans = (dans + ans[i]) % mod;
}
cout << dans;
return 0;
}

D. Steps to One的更多相关文章

  1. animation-timing-function: steps() 详解

    在应用 CSS3 渐变/动画时,有个控制时间的属性 <animation-timing-function> .它的取值中除了常用到的 贝萨尔曲线以外,还有个让人比较困惑的 steps()  ...

  2. CSS3 Animation 帧动画 steps()

    @keyframes fn{ 0%{} 100%{} } CSS3的Animation有八个属性 animation-name :动画名 fn animation-duration:时间 1s ani ...

  3. SAML 2.0 setup steps, 效果图

    Steps of setting up SAML SSO. 效果图 # Registry a Identity Provider services in:(Might need purchase) I ...

  4. 【译】css动画里的steps()用法详解

    原文地址:http://designmodo.com/steps-c... 原文作者:Joni Trythall 我想你在css 动画里使用steps()会和我一样有很多困惑.一开始我不清楚怎样使用它 ...

  5. css3动画中的steps值详解

    css3的动画的animation-timing-function属性定义了动画的速度曲线,一般的速度曲线大家都知道,什么ease,linear,ease-in,ease-out,还有自定义贝塞尔曲线 ...

  6. steps animation

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. sdutoj 2623 The number of steps

    http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2623 The number of steps ...

  8. SAP NWBC for HTML and Desktop configuration steps[From sdn]

    Summary :- This dcoumnenst conatin the information about requirement , hardware , configuration step ...

  9. 【转载】7 Steps for Calculating the Largest Lyapunov Exponent of Continuous Systems

    原文地址:http://sprott.physics.wisc.edu/chaos/lyapexp.htm The usual test for chaos is calculation of the ...

  10. BSGS算法_Baby steps giant steps算法(无扩展)详解

    Baby Steps-Varsity Giant Step-Astronauts(May'n・椎名慶治) 阅读时可以听听这两首歌,加深对这个算法的理解.(Baby steps少女时代翻唱过,这个原唱反 ...

随机推荐

  1. 使用Libusb和hidapi测试HID设备

    一.测试中断或者Bulk传输: 首先要使用Libusb打印出HID设备的Endpoint查看是否支持中断或者Bulk传输模式:如果支持的话才可以进一步测试: 因为HID设备在插入的时候无需安装,并且一 ...

  2. 记maven打包加入外部jar后tomcat运行失败问题

    环境:maven 3.8.0 .tomcat 8.5.30 因为项目需要额外的引用外部jar,需要打包到war中. 所以在pom中加入了 <webResources> <resour ...

  3. Linux 第五节 (shell脚本while循环,case,计划任务,用户及权限)

    #!/bin/bash #this is a test script PRICE=$(expr $RANDOM % 1000)   //将随机得出的数字取余 TIMES=0 while true do ...

  4. 用“餐厅打包”的故事说明白Python里面的自定义函数

    注:博主并非Python专业程序员,年龄12岁,Python龄不到1岁,才疏学浅,如有错误还请大佬指教! 希望能通过本专栏帮助到一些Python小白! 嗨~大家好!上篇博文咱们说了,万一有一些上万行才 ...

  5. 牛客算法进阶——树形dp

    1. 小G有一个大树(求树的重心) 删除该点后最大连通块的节点数最小 设f[x]表示以x为根的子树大小,那么删除x之后的各子树大小为f[to]和n-f[x] 求max(max(f[to]),n-f[x ...

  6. [canvas]ncaught TypeError: Cannot read properties of null (reading 'getContext')

    相信你和我一样是直接复制大佬的js代码(笑) ------------ 主要问题在于:js先加载完了,html才加载,导致js获取不了html的对象 解决办法: 把  <head />  ...

  7. OSPF配置知识总结2(单区域)

    OSPF配置知识总结2 静态路由有静态路由的好处,但也有弊端,牵一发动全身,在一个路由路径上,只要变一个,其他所有的路由器上的静态路由都要跟着改变. 用动态路由OSPF很简单就能解决这个问题.如下: ...

  8. windows下的故障自愈程序,可以实现进程,kafka按时间段判断状态,日志分级

    self-healing 1.使用python3.11写的一个故障自愈程序. 2.本程序在window2019 server运行测试通过 3.通过监控java程序里的详细启动包名来判断进程是否存在 4 ...

  9. oracle之PGA相关的sql

    在上篇文章中初步介绍了关于pga的基础知识,阅读了其他很多关于pga的内容,今天总结一些关于pga的sql和其他知识. 在网上找了相关资料整理而来,可能有点乱,先码上后再整理下. https://bl ...

  10. linux的打开文件标志O_CLOEXEC

    当没有这个标志,打开文件时,得到的fd, 将会被子进程继承,并且子进程会获得这个fd的读写能力. 往往父进程打开的文件,不希望子进程读写,所以,子进程启动之后,可以手动关闭fd. 但是关闭fd的操作不 ...