CF1139D Steps to One 题解【莫比乌斯反演】【枚举】【DP】
反演套 DP 的好题(不用反演貌似也能做
Description
Vivek initially has an empty array \(a\) and some integer constant \(m\).
He performs the following algorithm:
- Select a random integer \(x\) uniformly in range from \(1\) to \(m\) and append it to the end of \(a\).
- Compute the greatest common divisor of integers in \(a\).
- In case it equals to \(1\), break
- Otherwise, return to step \(1\).
Find the expected length of \(a\). It can be shown that it can be represented as \(\frac PQ\) where \(P\) and \(Q\) are coprime integers and \(Q\neq 0\pmod{10^9+7}\). Print the value of \(P\cdot Q^{-1}\pmod{10^9+7}\).
Input
The first and only line contains a single integer \(m\)(\(1\le m\le 100000\)).
Output
Print a single integer — the expected length of the array \(a\) written as \(P\cdot Q^{-1}\pmod{10^9+7}\).
Examples
input
1
output
1
input
2
output
2
input
4
output
333333338
Note
In the first example, since Vivek can choose only integers from \(1\) to \(1\), he will have \(a=[1]\) after the first append operation, and after that quit the algorithm. Hence the length of \(a\) is always \(1\), so its expected value is \(1\) as well.
In the second example, Vivek each time will append either \(1\) or \(2\), so after finishing the algorithm he will end up having some number of \(2\)'s (possibly zero), and a single \(1\) in the end. The expected length of the list is \(1⋅\frac 12+2⋅\frac 1{2^2}+3⋅\frac 1{2^3}+\dots =2\).
题意
每一步在 \(1\sim m\) 中任选一个整数,问期望多少步后选出的数的最大公约数是 \(1\)。答案对 \(1\ 000\ 000\ 007\) 取模。
题解
因为每一步不会让已经选了的元素的 \(\gcd\) 和变大,因此认为是一个除自环外的有向无环图。对于自环我们很好处理,所以把它看成是一道期望 DP。
令 \(f[i]\) 表示当前的 \(\gcd\) 和为 \(i\),到 \(\gcd\) 和为 \(1\) 的状态的期望步数。因此把状态转移方程写出来
\]
这样的转移是 \(O(m^2)\) 的。但是我们发现,对于很多 \(j\),\(\gcd(i,j)\) 都是相等的,因此我们把这样的数整合到一起。
令 \(F(n)\) 表示 \(1\sim m\) 中有多少个数 \(i\) 满足 \(\gcd(x,i)=n\),其中视 \(x\) 为常数。
则计算 \(f[i]\) 就转化为了
\]
这样差不多就把枚举优化到了 \(\log n\) 的 \(d|i\)。
考虑怎么计算 \(F(n)\)
\]
令 \(G(n)=\sum_{n|d}F(d)\),则
G(n)&=\sum_{n|d}F(d)\\
&=\sum_{n|d}\sum_{i=1}^m[\gcd(x,i)=d]\\
&=\sum_{i=1}^m[n|\gcd(x,i)]\\
?&=\sum_{i=1}^{\left\lfloor\frac mn\right\rfloor}\left[1|\gcd\left(\frac xn,i\right)\right]
\end{aligned}
\]
实际上这样是有问题的,因为(在后面)无法保证 \(n|x\),此时 \(G(n)\) 就一定为 \(0\) 了。
我们再多化一步:
G(n)&=\sum_{i=1}^{\left\lfloor\frac mn\right\rfloor}\left[1|\gcd\left(\frac xn,i\right)\right][n|x]\\
&=\left\lfloor\frac mn\right\rfloor\cdot[n|x]
\end{aligned}
\]
根据 \(G(n)=\sum_{n|d}F(d)\),我们反演到 \(F\),得
F(n)&=\sum_{n|d}\mu\left(\frac dn\right)G(d)\\
&=\sum_{i=1}^{\left\lfloor\frac mn\right\rfloor}\mu(i)G(ni)\\
&=\sum_{i=1}^{\left\lfloor\frac mn\right\rfloor}\mu(i)\left\lfloor\frac{m}{ni}\right\rfloor[(ni)|x]
\end{aligned}
\]
我们发现后面的布尔表达式可以当作条件。原本的条件本来就是 \(\to +\infty\) 的,只不过超过了 \(\left\lfloor\frac mn\right\rfloor\) 没有意义。因此直接把条件换成 \([(ni)|x]\) 即可。又因为 \(n|x\) 在上面的枚举过程中是成立的,同时可以转化为 \(\left[i|\frac xn\right]\)。
\]
这样的一次枚举是 \(O\left(d\left(\frac xn\right)\right)\) 的,由于 \(1\sim m\) 的约数个数和均摊是 \(O(\log m)\) 的,其中最多的有 \(128\) 个约数,但是这样的数肯定不是很多,并且其中很多被枚举到的数都是质因数,迭代一下并不会造成很大的复杂度。
然后我们需要再把状态转移方程稍微转化一下,把 \(f[i]\) 移到左边
f[i]&=1+\frac{\sum_{d|i,d<i}f[d]\times F(d)+f[i]\times F(i)}n,x=i\\
\frac{n-F(i)}{n}\cdot f[i]&=1+\frac{\sum_{d|i,d<i}f[d]\times F(d)}n,x=i\\
f[i]&=\frac{n+\sum_{d|i,d<i}f[d]\times F(d)}{n-F(i)},x=i
\end{aligned}
\]
就得到了真正的转移方程。
时间复杂度 \(O(m\log^2 m)\)。
Code:
#include<cstdio>
#include<cstring>
#include<vector>
#define ll long long
#define p 1000000007
using std::vector;
vector<int> v[100100];//约数用 vector 存一下,每次 √m 枚举不是很稳
ll qpow(ll x,ll y)
{
ll ans=1;
while(y)
{
if(y&1)
ans=ans*x%p;
x=x*x%p;
y>>=1;
}
return ans;
}
bool is[100100];
int pri[100100],mu[100100],cnt=0;
ll f[100100];
int n;
int calc(int x,int y)//1~n 中 gcd(x,i)=y 的数的个数
{
int g=x/y,ans=0;
for(int i=0;i<v[g].size();++i)
ans+=mu[v[g][i]]*(n/v[g][i]/y);
return ans;
}
int main()
{
scanf("%d",&n);
f[1]=1;
mu[1]=1;
for(int i=2;i<=n;++i)
{
if(!is[i])
{
pri[++cnt]=i;
mu[i]=-1;
}
for(int j=1;j<=cnt&&i*pri[j]<=n;++j)
{
is[i*pri[j]]=1;
if(i%pri[j])
mu[i*pri[j]]=-mu[i];
else
{
mu[i*pri[j]]=0;
break;
}
}
}
for(int i=1;i<=n;++i)
for(int j=i;j<=n;j+=i)
v[j].push_back(i);
ll ans=1,inv=qpow(n,p-2);
for(int i=2;i<=n;++i)
{
for(int j=0;j<v[i].size()-1;++j)
f[i]=(f[i]+calc(i,v[i][j])*f[v[i][j]]%p)%p;
f[i]=(f[i]*inv+1)%p;
ll g=n-calc(i,i);
f[i]=f[i]*n%p*qpow(g,p-2)%p;
ans=(ans+f[i])%p;
}
printf("%lld\n",ans*qpow(n,p-2)%p);
return 0;
}
CF1139D Steps to One 题解【莫比乌斯反演】【枚举】【DP】的更多相关文章
- CF1139D Steps to One (莫比乌斯反演 期望dp)
\[ f[1] = 0 \] \[ f[i] = 1 + \frac{1}{m} \sum_{j = 1} ^ n f[gcd(i, j)] \ \ \ \ \ \ (i != 1) \] 然后发现后 ...
- Problem b 莫比乌斯反演+枚举除法的取值
莫比乌斯反演+枚举除法的取值 第二种形式: f(n)表示gcd(x,y)=n的数量. F(n)表示gcd(x,y)是n的倍数的数量. /** 题目:Problem b 链接:https://vjudg ...
- 【51nod1678】lyk与gcd(莫比乌斯反演+枚举因数)
点此看题面 大致题意: 一个长度为\(n\)的数组,实现两种操作:单点修改,给定\(i\)求\(\sum_{j=1}^na_j[gcd(i,j)=1]\). 莫比乌斯反演 考虑推一推询问操作的式子: ...
- 【bzoj3529】[Sdoi2014]数表 莫比乌斯反演+离线+树状数组
题目描述 有一张n×m的数表,其第i行第j列(1 <= i <= n ,1 <= j <= m)的数值为能同时整除i和j的所有自然数之和.给定a,计算数表中不大于a的数之和. ...
- 【bzoj3561】DZY Loves Math VI 莫比乌斯反演
题目描述 给定正整数n,m.求 输入 一行两个整数n,m. 输出 一个整数,为答案模1000000007后的值. 样例输入 5 4 样例输出 424 题解 莫比乌斯反演 (为了方便,以下公式默认$ ...
- 【bzoj4407】于神之怒加强版 莫比乌斯反演+线性筛
题目描述 给下N,M,K.求 输入 输入有多组数据,输入数据的第一行两个正整数T,K,代表有T组数据,K的意义如上所示,下面第二行到第T+1行,每行为两个正整数N,M,其意义如上式所示. 输出 如题 ...
- 【bzoj4816】[Sdoi2017]数字表格 莫比乌斯反演
题目描述 Doris刚刚学习了fibonacci数列.用f[i]表示数列的第i项,那么 f[0]=0 f[1]=1 f[n]=f[n-1]+f[n-2],n>=2 Doris用老师的超级计算机生 ...
- [Noi2010]能量采集 (莫比乌斯反演)
[Noi2010]能量采集 Description 栋栋有一块长方形的地,他在地上种了一种能量植物,这种植物可以采集太阳光的能量.在这些植物采集能量后, 栋栋再使用一个能量汇集机器把这些植物采集到的能 ...
- 【HDU1695】GCD(莫比乌斯反演)
[HDU1695]GCD(莫比乌斯反演) 题面 题目大意 求\(a<=x<=b,c<=y<=d\) 且\(gcd(x,y)=k\)的无序数对的个数 其中,你可以假定\(a=c= ...
随机推荐
- Java Thread系列(九)Master-Worker模式
Java Thread系列(九)Master-Worker模式 Master-Worker模式是常用的并行设计模式. 一.Master-Worker 模式核心思想 Master-Worker 系统由两 ...
- linux每天一小步---mv命令详解
1 命令功能 mv命令用来移动文件及目录或者重命名文件及目录,它是move的缩写,cp命令与mv命令在很多功能上都非常相似,但是又具有很大的区别,其中组大的区别在于cp命令的使用会保留源文件和目录,而 ...
- git 创建管理远程分支
1.远程分支就是本地分支push到服务器上的时候产生的.比如master就是一个最典型的远程分支(默认). 1 $: git push origin master 除了master之外,我们还可以 ...
- Internal error(U783)
今天打开代码时一个单元文件报这个错误Internal error(U783),不知道什么原因,然后多次关闭打开后,又没报这个错误了,记录下 http://www.aiuxian.com/article ...
- Visual Studio 2017(VS2017) 企业版 Enterprise 注册码
Visual Studio 2017(VS2017) 企业版 Enterprise 注册码:NJVYC-BMHX2-G77MM-4XJMR-6Q8QF 终于等到你,最强 IDE Visual Stud ...
- TFS签入代码时,自动修改工作项的状态为“已解决”
Visual Studio中有一个很酷的功能,就是签入代码到TFS库时,可以关联相应的工作项,实现代码与工作项(需求.任务.Bug等)的关联,从而实现代码的跟踪. 在关联工作项的过程中,如果工作项具备 ...
- [Erlang31]Erlang trace总结
在一个并行的世界里面,我们很难做到单步断点调试来定位问题(太多的消息飞来飞去),Erlang设计者也深刻体会到这一点,推出了另一个trace机制. 通过这个trace,你可以: .特定进程集内的函数调 ...
- ansible 之条件语句 when
注册变量: 变量的另一个用途是将一条命令的运行结果保存到变量中,供后面的playbook使用.例如: - hosts: webservers tasks: - shell: /usr/bin/foo ...
- datatime模块
https://www.cnblogs.com/cindy-cindy/p/6720196.html
- KVM到KVM之v2v迁移
1.源KVM虚拟主机node1 (1).查看源KVM虚拟主机上的虚拟机列表,本文计划将oeltest01虚拟机迁移到其它KVM虚拟主机中. (2).查看oeltest01虚拟机磁盘文件位置/data/ ...