反演套 DP 的好题(不用反演貌似也能做

Description

Vivek initially has an empty array \(a\) and some integer constant \(m\).

He performs the following algorithm:

  1. Select a random integer \(x\) uniformly in range from \(1\) to \(m\) and append it to the end of \(a\).
  2. Compute the greatest common divisor of integers in \(a\).
  3. In case it equals to \(1\), break
  4. 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\) 的状态的期望步数。因此把状态转移方程写出来

\[f[i]=1+\frac{\sum_{j=1}^m f[\gcd(i,j)]}m
\]

这样的转移是 \(O(m^2)\) 的。但是我们发现,对于很多 \(j\),\(\gcd(i,j)\) 都是相等的,因此我们把这样的数整合到一起。

令 \(F(n)\) 表示 \(1\sim m\) 中有多少个数 \(i\) 满足 \(\gcd(x,i)=n\),其中视 \(x​\) 为常数。

则计算 \(f[i]\) 就转化为了

\[f[i]=1+\frac{\sum_{d|i}f[d]\times F(d)}n,x=i
\]

这样差不多就把枚举优化到了 \(\log n\) 的 \(d|i​\)。

考虑怎么计算 \(F(n)\)

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

令 \(G(n)=\sum_{n|d}F(d)\),则

\[\begin{aligned}
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\) 了。

我们再多化一步:

\[\begin{aligned}
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\),得

\[\begin{aligned}
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]\)。

\[F(n)=\sum_{i|\frac xn}\mu(i)\left\lfloor\frac{m}{ni}\right\rfloor
\]

这样的一次枚举是 \(O\left(d\left(\frac xn\right)\right)\) 的,由于 \(1\sim m\) 的约数个数和均摊是 \(O(\log m)\) 的,其中最多的有 \(128\) 个约数,但是这样的数肯定不是很多,并且其中很多被枚举到的数都是质因数,迭代一下并不会造成很大的复杂度。

然后我们需要再把状态转移方程稍微转化一下,把 \(f[i]\) 移到左边

\[\begin{aligned}
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】的更多相关文章

  1. CF1139D Steps to One (莫比乌斯反演 期望dp)

    \[ f[1] = 0 \] \[ f[i] = 1 + \frac{1}{m} \sum_{j = 1} ^ n f[gcd(i, j)] \ \ \ \ \ \ (i != 1) \] 然后发现后 ...

  2. Problem b 莫比乌斯反演+枚举除法的取值

    莫比乌斯反演+枚举除法的取值 第二种形式: f(n)表示gcd(x,y)=n的数量. F(n)表示gcd(x,y)是n的倍数的数量. /** 题目:Problem b 链接:https://vjudg ...

  3. 【51nod1678】lyk与gcd(莫比乌斯反演+枚举因数)

    点此看题面 大致题意: 一个长度为\(n\)的数组,实现两种操作:单点修改,给定\(i\)求\(\sum_{j=1}^na_j[gcd(i,j)=1]\). 莫比乌斯反演 考虑推一推询问操作的式子: ...

  4. 【bzoj3529】[Sdoi2014]数表 莫比乌斯反演+离线+树状数组

    题目描述 有一张n×m的数表,其第i行第j列(1 <= i <= n ,1 <= j <= m)的数值为能同时整除i和j的所有自然数之和.给定a,计算数表中不大于a的数之和. ...

  5. 【bzoj3561】DZY Loves Math VI 莫比乌斯反演

    题目描述 给定正整数n,m.求   输入 一行两个整数n,m. 输出 一个整数,为答案模1000000007后的值. 样例输入 5 4 样例输出 424 题解 莫比乌斯反演 (为了方便,以下公式默认$ ...

  6. 【bzoj4407】于神之怒加强版 莫比乌斯反演+线性筛

    题目描述 给下N,M,K.求 输入 输入有多组数据,输入数据的第一行两个正整数T,K,代表有T组数据,K的意义如上所示,下面第二行到第T+1行,每行为两个正整数N,M,其意义如上式所示. 输出 如题 ...

  7. 【bzoj4816】[Sdoi2017]数字表格 莫比乌斯反演

    题目描述 Doris刚刚学习了fibonacci数列.用f[i]表示数列的第i项,那么 f[0]=0 f[1]=1 f[n]=f[n-1]+f[n-2],n>=2 Doris用老师的超级计算机生 ...

  8. [Noi2010]能量采集 (莫比乌斯反演)

    [Noi2010]能量采集 Description 栋栋有一块长方形的地,他在地上种了一种能量植物,这种植物可以采集太阳光的能量.在这些植物采集能量后, 栋栋再使用一个能量汇集机器把这些植物采集到的能 ...

  9. 【HDU1695】GCD(莫比乌斯反演)

    [HDU1695]GCD(莫比乌斯反演) 题面 题目大意 求\(a<=x<=b,c<=y<=d\) 且\(gcd(x,y)=k\)的无序数对的个数 其中,你可以假定\(a=c= ...

随机推荐

  1. 用JQ去实现一个轮播效果

    前提:用JQ去实现轮播效果一步步的做一个梳理. 首先肯定是轮播的HTML和CSS样式了: <body> <div class="pic"> <div ...

  2. Hadoop中Writable类之四

    1.定制Writable类型 Hadoop中有一套Writable实现,例如:IntWritable.Text等,但是,有时候可能并不能满足自己的需求,这个时候,就需要自己定制Writable类型. ...

  3. (转)centos liveCD liveDVD netinstall minimal DVD1 DVD2 版本区别

    LiveCD 和 LiveDVD 是可以直接光盘运行系统,但不能安装,两者差别在于容量大小,dvd包含的软件要多一些. netinstall 是用于网络安装和系统救援的镜像文件. minimal 这个 ...

  4. Java动态代理(三)——模拟AOP实现

    以下案例模拟AOP实现 目录结构 接口PersonService package com.ljq.service; public interface PersonService { public vo ...

  5. XXX 不是当前用户的有效责任,请联系您的系统管理员

    EBS中,有时进入一些基于OA Framework 的Web页面时,会出现这种现象: XXX  不是当前用户的有效责任,请联系您的系统管理员 ( or: xxx is not a valid resp ...

  6. Spring 事务管理案例

    事务管理简介   Spring 事务管理有两种方式:一种是编程式事务管理,即通过编写代码实现事物管理,包括定义事务的开始,程序正常执行后的事物提交,异常时进行的事务回滚.另一种是基于AOP技术实现的声 ...

  7. XML--将XML中数据提取出转换成表

    DECLARE @xml XMLSET @xml='<Students>    <Student  id="1001">        <name&g ...

  8. 使用dockerfile文件创建镜像时docker build没有反应

    问题: 先 docker pull centos:7 拉取了一个官方的基础镜像,为后续创建jdk8镜像做准备,在创建如下的dockerfile文件 执行docker build -t jdk_8u19 ...

  9. 什么是ODBC和JDBC?

    jdbc是使用通过JAVA的数据库驱动直接和数据库相连,而jdbc-odbc连接的是ODBC的数据源,真正与数据库建立连接的是ODBC! 建议使用JDBC直接连接,同时最好使用连接池! JDBC 是 ...

  10. asp.net——Josn转DataTable(转)

    使用UI框架开发的时候就常常用到DataTable转Json的情况,但是最近完成一个微信公众号开发的项目,需要把微信接口传过来的json值作为转为DataTable后绑定到服务器控件上. 在网上找了很 ...