【期望dp 质因数分解】cf1139D. Steps to One

有一种组合方向的考虑有没有dalao肯高抬啊?

题目大意

有一个初始为空的数组$a$,按照以下的流程进行操作:

  • 在$1\cdots m$中等概率选出一个数$x$并添加到$a$的末尾
  • 如果$a$中所有元素的$\gcd=1$则完成这个数组$a$的修改
  • 重复这一过程

求数组$a$的期望长度,$m \le 10^5,\mod 10^9+7$


题目分析

质因数分解的期望dp题

以下介绍的两个做法中,第一个做法本人不会所以  求助会做的dalao麻烦高抬一手   ;

第二个做法是对推得的dp式子质因数分解求解————当然网上更多的是莫比乌斯反演的做法,此处就不介绍了。

未完的做法一:组合考虑

考虑计算$f(d)$为:数组$a$的前$len-1$个(也即结束前的那一序列)$\gcd=d$时,对答案的期望长度贡献。

那么枚举结束前的长度$i$,记$h(d)$为$1\cdots m$中与$d$互质的数的个数;$g(i,d)$为一个$\gcd=d$的长度为$i$的序列的概率,有$f(d)=\sum\limits_{i=1}^{∞}(i+1)\times g(i,d)\times h(d)$。

当然,这样的式子远远不够。$h(d)$的计算非常轻松但是问题在于$g(i,d)$有没有什么组合上的表达方式。我最初以为$g(i,d)=\lfloor\frac{m}{d}\rfloor^{i-1}\times \frac{1}{m}$,意即将序列看做是无序取入的集合,确保$i-1$个元素都是$\{d,2d,3d\cdots\}$,并钦点一个$d$.但是这个处理有两个问题:1.序列不能够这样看成无序集合;2.并不是必须要有一个$d$才能使数组的$\gcd=d$,例如$\{2d,3d,5d\}$就有$\gcd=d$。

这个方向大概不太能行吧,为求出式子,$g(i,d)$可能还有更严苛的表达限制。

做法二:质因数分解

由于这里的长度是无穷的,所以处理角度还当是从序列的$\gcd$入手。

记$f_d$为当前数组已经$\gcd=d$,到达$\gcd=1$的状态的期望步数。(这个状态要比我上面那个状态要优秀地多)

容易得到转移  $f_d=1+\frac{1}{m} \sum\limits_{i=1}^mf_{\gcd(i,d)}$

稍作化简得到  $f_d=1+\frac{1}{m} \sum\limits_{i\mid d,i\ne d}(f_i\times c(i,d)+\lfloor\frac{m}{d}\rfloor f_d)$,其中$c(i,d)=\sum\limits_{j=1}^m[\gcd (d,j)=i]$.

通过移项,有  $f_d=\frac{1+\frac{1}{m} \sum\limits_{i\mid d,i\ne d}f_i\times c(i,d)}{1-\frac{1}{m}\lfloor\frac{m}{d}\rfloor}$

那么对于这里$c(i,d)$的处理,就有很多方法了。这里介绍质因数分解的做法:

由于  $c(i,d)=\sum\limits_{j=1}^m[\gcd (d,j)=i]=\sum\limits_{j=1}^{\lfloor \frac{m}{i} \rfloor}[\gcd (\lfloor\frac{d}{i}\rfloor,j)=1]$,考虑子问题:$1\cdots c$中与$q$互质的数的个数。

那么将$q$唯一分解,有$q=p_1^{k_1}p_2^{k_2}\cdots$。注意到实际上我们只关心$p_i$而不关心$k_i$,所求的也就是$1\cdots c$中不存在任何$p_i$因数的数的个数。至此转为一个经典容斥问题,可以预处理出$r$个素因数再$2^r$容斥解决。

接下来是一些题外话,

上面提到的分解素因数的过程,理论上由于$10^5$内的数最多只有$6$个素因数,那么枚举每个素数检查是否为其因数的方法看上去也不算太差,

然而获得了1700ms+的“好”成绩:

一开始我还以为是$2^r$的dfs飞天了,然而后来意识到上述的这个素数分解的方法常数的确是巨大的……

可以这么看:对于一个要处理的数$x$,共约要遍历$\frac{x}{\ln x}$个素数。那么在这一部分上的总期望时间花费就大致是$\frac{m^2\sqrt m}{\ln m}$(好像这个上界太松没什么价值?)。

总之判断约数是否为质数的方法就要快很多:

 1 #include<bits/stdc++.h>
 2 #define MO 1000000007
 3 typedef long long ll;
 4 typedef std::vector<int> vec;
 5 const int maxn = 100035;
 6 
 7 int n,num,cnt,pr[maxn],phi[maxn];
 8 bool vis[maxn];
 9 ll ans,f[maxn];
10 vec fac[maxn],opt;
11 
12 void makePrime()
13 {
14     phi[1] = 1;
15     for (int i=2; i<maxn; i++)
16     {
17         if (!vis[i]) pr[++pr[0]] = i, phi[i] = i-1;
18         for (int j=1,chk=1; j<=pr[0]&&i*pr[j]<maxn&&chk; j++)
19             if (pr[j]%i) phi[i*pr[j]] = phi[i]*(pr[j]-1);
20             else chk = 0, phi[i*pr[j]] = phi[i]*pr[j];
21     }
22     for (int i=1; i<maxn; i++)
23         for (int j=i; j<maxn; j+=i) fac[j].push_back(i);
24 }
25 int qmi(int a, int b)
26 {
27     int ret = 1;
28     for (; b; b>>=1,a=1ll*a*a%MO)
29         if (b&1) ret = 1ll*ret*a%MO;
30     return ret;
31 }
32 void dfs(int x, int c, int t)
33 {
34     if (x==opt.size()) cnt += ((t&1)?-num/c:num/c);
35     else{
36         dfs(x+1, c, t);
37         dfs(x+1, c*opt[x], t+1);
38     }
39 }41 int calc(int p, int d)
42 {
43     vec().swap(opt), p /= d, num = n/d;
44     for (int pri; p>1; )
45     {
46         pri = fac[p][1];
47         if (vis[pri]) break;
48         opt.push_back(pri);
49         while (p%pri==0) p /= pri;
50     }
51     cnt = 0, dfs(0, 1, 0);
52     return cnt;
53 }
54 int main()
55 {
56     scanf("%d",&n), ans = 1, f[1] = 0;
57     makePrime();
58     for (int i=2; i<=n; i++)
59     {
60         int lwr = (1-1ll*qmi(n, MO-2)*(n/i)%MO+MO)%MO;
61         for (int j=1; j<fac[i].size()-1; j++)
62             f[i] = (f[i]+1ll*f[fac[i][j]]*calc(i, fac[i][j])%MO)%MO;
63         f[i] = 1ll*(1ll*f[i]*qmi(n, MO-2)%MO+1)*qmi(lwr, MO-2)%MO;
64         ans = (ans+f[i]+1)%MO;
65     }
66     printf("%lld\n",1ll*ans*qmi(n, MO-2)%MO);
67     return 0;
68 }

 

 

END

转载于:https://www.cnblogs.com/antiquality/p/10742748.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值