首页 > 其他分享 >P9611 题解

P9611 题解

时间:2024-10-05 11:01:00浏览次数:9  
标签:lfloor int 题解 个数 rfloor times sqrt P9611

题目大意


从题目可知,本题要求求出\(l \sim r\)的因子个数和。

题目分析


我们可以将这个问题分解为两个问题,变成求\(1 \sim r\)的因子个数和减去\(1 \sim l-1\)的因子个数和,然后我们考虑如何求\(1 \sim n\)的因子个数和

首先,如果正着做很难的话,我们可以考虑反着做

对于一个数\(x\),因为在\(1 \sim n\)中,有\(\lfloor n \div x \rfloor\)个数能被\(x\)整除,所以它对于因子个数的贡献为\(\lfloor n \div x \rfloor\)。

根据这个原理,我们可以写出一个时间复杂度为\(\mathcal{O}\left(n\right)\)的TLE程序:

#include<bits/stdc++.h>
#define int long long 
const int N = 1e5+5;
const int Mod = 1e9+7;
using namespace std;
int l, r;
int f(int n)
{
    int cnt = 0;
    for(int i = 1; i <= n; i++)
    {
        cnt += n / i;
    }
    return cnt;
}
signed main()
{
    cin >> l >> r;
    cout << f(r) - f(l - 1) << endl;
    return 0;
}

看来我们要把时间复杂度降到\(\mathcal{O}\left(\sqrt n\right)\)才可以。

可以想到,对于每一个数,他的因数必然是成对的(平方数除外),那么我们只需要遍历到\(\lfloor \sqrt n \rfloor\),最后再乘以二即可。但是我们会发现,这样计算的结果比正确结果大很多,为什么呢?因为会有重复。所以我们要把重复的减去,这样才可以得到正确的结果。

那么现在我们要考虑哪些部分会重复。

我们以\(n\)为\(9\)为例:

数字 因数
\(1\) \(1\)
\(2\) \(1,2\)
\(3\) \(1,3\)
\(4\) \(1,2,4\)
\(5\) \(1,5\)
\(6\) \(1,2,3,6\)
\(7\) \(1,7\)
\(8\) \(1,2,4,8\)
\(9\) \(1,3,9\)

我们的贡献统计是这样的:

数字 贡献数字对
\(1\) \(1\times\red1,1\times2,1\times3,1\times4,1\times5,1\times6,1\times7,1\times8,1\times9\)
\(2\) \(\red2\times\red1,2\times\red2,2\times3,2\times4\)
\(3\) \(\red3\times\red1,\red3\times\red2,3\times\red3\)

通过观察重复的标红部分,我们发现每个数刚好重复了\(\lfloor \sqrt n \rfloor\)次!为什么会这样呢?因为每一个数乘上另外一个数,如果反过来还在表里面,那么就会重复。在表里面有\(\lfloor \sqrt n \rfloor\)个数,每个数会重复\(\lfloor \sqrt n \rfloor\)次,所以总共会重复\(\lfloor \sqrt n \rfloor\times\lfloor \sqrt n \rfloor\)次。

于是我们便可以完成最后的代码:

AC Code


#include<bits/stdc++.h>
#define int long long 
const int N = 1e5+5;
const int Mod = 1e9+7;
using namespace std;
int l, r;
int f(int n)
{
    int cnt = 0, sqr = sqrt(n);
    for(int i = 1; i <= sqr; i++)
    {
        cnt += n / i;
    }
    return cnt * 2 - sqr * sqr;
}
signed main()
{
    cin >> l >> r;
    cout << f(r) - f(l - 1) << endl;
    return 0;
}

标签:lfloor,int,题解,个数,rfloor,times,sqrt,P9611
From: https://www.cnblogs.com/jackzhang2013/p/18447685

相关文章

  • CF1108F题解
    传送门:https://codeforces.com/problemset/problem/1108/F求出最小生成树后处理出任意两点间边的最大值,这里可以用倍增或者树刨。然后用不在生成树上的边去替换,如果边权和边两端点路径最大边值相同则最小生成树不唯一,需要将边权\(+1\)。实现比较简单,写了一遍就过了。#include<b......
  • 题解:CF704B Ant Man
    从这来的,套路都一样,预设型DP。把那个式子拆开,看每个数单独的贡献。一个数比它左边的数小,它的贡献就是:\(-x_i+b_i\)比它左边的数大,它的贡献就是:\(x_i+a_i\)比它右边的数小,它的贡献就是:\(-x_i+d_i\)比它右边的数大,它的贡献就是:\(x_i+c_i\)即:intGl(inti){//>......
  • 题解:P8973 『GROI-R1』 继续深潜,为了同一个梦想
    换根dp模板题。\(f_i\)是在以\(i\)为根的子树中,以\(i\)为链的一个端点且\(i\)在点集中的合法点集个数。\(ans_i\)表示包含\(i\)的合法点集个数。当\(x\)为树根时:\[ans_x={f_x\choose2}-\sum_{s\inson}{2f_s+1\choose2}+f_x\]简单解释一下,\({f_x\ch......
  • [题解][洛谷P3584] LAS
    题目描述有n个蛋糕和n个人,每个蛋糕的热量是Ci。第i个人可以选择吃第i或第i+1个蛋糕,第n个人可以选择吃第n或第1个蛋糕。若一个蛋糕被两个人吃,那么每个人得到的热量是Ci/2.若一个人改变自己的选择,得到的热量增加,那么他会不满意。试输出让所有人满意的解,输出每个人吃蛋糕的序号......
  • Centos7 停止维护之后 升级gcc||找不到devtoolset-8-gcc* 问题解决方案
    为了去小米澎湃互联组,感觉必须得拿下linux网络编程,今天第一步这个centos就给我拉了坨大的问题实质SCL源没换,相信你也在别的教程上看到要安装centos-release-scl吧?有坑!安装完成后在/etc/yum.repos.d目录下会出现CentOS-SCLo-scl.repo和CentOS-SCLo-scl-rh.repo两个文件,......
  • [题解][洛谷P1578] 奶牛浴场
    题目描述在长宽为L,W的二维平面上有n个障碍点,试找到一个不覆盖任何障碍点(但点可以在边缘线上的)面积最大的矩形(长宽均与坐标轴平行)。输出面积。题意分析n的范围在5e3,考虑O(n2)的做法。易得面积最大的矩形四条边要么有障碍点,要么覆盖的边界。否则四条边可以继续扩展,面积会变得更......
  • [题解][洛谷P1633] 二进制
    题目描述有三个整数A,B,C,构造三个整数X,Y,Z满足:1.A,B,C在二进制下1的数量分别与X,Y,Z相等;2.X,Y,Z在二进制下的长度不超过A,B,C的最大长度;3.X+Y=Z。输出Z的最小值,若不存在Z,输出-1。题意分析首先考虑X,Y在什么情况下会使1的数量发生改变。设x,y,z分别表示X,Y,Z中1的数量,则......
  • CF542C题解
    传送门:https://codeforces.com/problemset/problem/542/C我们把序列的映射关系看作\(i\rightarrowf(i)\)的边,要使\(f(f(i))=f(i)\),显然存在\(i\)点距离不超过\(1\)的长度为\(1\)的自环。推广到\(f^{(k)}(x)\)满足题意则会在距离\(x\)点距离不超过\(k\)的长度为\(k\)的环。我们......
  • CF242D题解
    传送门:https://codeforces.com/problemset/problem/242/D对于一个点,显然一旦达到额定值后,其他任何操作都无法使他减小,于是我们得出一个贪心性质,当且仅当一个点不合法时,才取增加他的值。同理,我们可以证明,问题必定有解,因为若一个点被选择,必定是因为其曾不合法,选择后使其\(+1\)合法,......
  • CF549B题解
    传送门:https://codeforces.com/problemset/problem/549/B和CF242C思路完全相同,对于一个点,显然一旦达到额定值后,其他任何操作都无法使他减小,于是我们得出一个贪心性质,当且仅当一个点不合法时,才取增加他的值。同理,我们可以证明,问题必定有解,因为若一个点被选择,必定是因为其曾不合法,......