嘘~ 正在从服务器偷取页面 . . .

洛谷P9148 除法题 题解


洛谷P9148 除法题 题解

题目链接:P9148 除法题

题意

给定大小为 $n$ 的集合 $a$,保证其中元素互不相同且均为正整数。

如果我们从中按顺序取出三个元素 $a, b, c$,则共有 $n \cdot (n-1) \cdot (n-2)$ 种不同的选择方案。

现在对于一种选择方案 $(a,b,c)$,定义其权值为 $\Bigl\lfloor\dfrac{a}{b}\Bigr\rfloor\Bigl\lfloor\dfrac{a}{c}\Bigr\rfloor\Bigl\lfloor\dfrac{b}{c}\Bigr\rfloor$。

你需要对所有的选择方案计算权值的总和,你只需输出这个总和对 $2^{32}$ 取模的结果。

注:$\lfloor a\rfloor$ 表示不大于 $a$ 的最大整数。如 $\lfloor 2.4\rfloor=2$、$\lfloor 5\rfloor=5$。

输入格式

第一行,一个正整数 $n$,表示序列的长度。

第二行,$n$ 个正整数 $a_1, a_2, \ldots, a_n$,每个数描述了集合 $a$ 的一个元素,这些数互不相同。

输出格式

输出一行一个整数,表示答案对 $2^{32}$ 取模的结果。

数据范围

对于 $100\%$ 的数据,$1 \le n, a_i \le 5000$。

很容易想到去枚举 $a,b$ ,但是仔细想想会发现 $c$ 很不好枚举

相反,如果我们枚举 $c$ ,考察它对哪些 $a,b$ 产生了贡献,这却是能做的。

可以发现,因为值域 $V$ 很小,所以 $\left\lfloor \frac{V}{c}\right\rfloor$ 的值域则更为小。

并且对于一个 $\left\lfloor \frac{a}{c}\right\rfloor$ ,它包含了 $[a_1, a_2]$ 内的所有整数,所有 $a \in [a_1,a_2]$ 的 $\left\lfloor \frac{a}{c}\right\rfloor$ 是相等的

那么对于 $\left\lfloor \frac{a}{c}\right\rfloor,\left\lfloor \frac{b}{c}\right\rfloor$ ,它包含了一个矩阵 $(a_1,b_1),(a_2,b_2)$ 内的所有点,这个统计很容易由二维差分做到。

分析一下时间复杂度。枚举 $c$ 这一部分的时间复杂度为

这里需要一个小知识

因此这部分的时间复杂度为 $\mathcal{O}(V^2)$ 。枚举 $a,b$ 计算答案的部分显然也是 $\mathcal{O}(V^2)$

总时间复杂度 $\mathcal{O}(V^2)$

代码:

#include <bits/stdc++.h>
using namespace std;
// #define int long long
// #define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(5e3 + 15))

const int m = 5000;
char vis[N]; int a[N],b[N][N];
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    int n; cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i], vis[a[i]] = true;
    for(int c = 1; c <= m; c++) if(vis[c])
    {
        for(int i = 1; i <= m; i++)
        {
            int a1 = c * i, a2 = min(c * (i + 1) - 1, m); if(a1 > a2) break;
            for(int j = 1; j <= m; j++)
            {
                int b1 = c * j, b2 = min(c * (j + 1) - 1, m); if(b1 > b2) break;
                up(a1, c + 1); up(b1, c + 1);
                b[a1][b1] += i * j; b[a1][b2 + 1] -= i * j;
                b[a2 + 1][b1] -= i * j; b[a2 + 1][b2 + 1] += i * j;
            }
        }
    }
    for(int i = 1; i <= m; i++)
        for(int j = 1; j <= m; j++) b[i][j] += b[i][j - 1];
    for(int i = 1; i <= m; i++)
        for(int j = 1; j <= m; j++) b[i][j] += b[i - 1][j];
    unsigned int res = 0;
    for(int i = 1; i <= m; i++)
        for(int j = 1; j <= m; j++)
            if(i > j && vis[i] && vis[j]) res += (i / j) * b[i][j];
    cout << res << '\n';
    return 0;
}

参考文献

[1] https://www.luogu.com.cn/blog/McHf/solution-p9148


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录