//打赏的js文件

勾股定理

勾股定理

题目

题目描述

\(A\) 最近在学习勾股定理的时候发现了一个很有趣的教学用具,于是买了一个回家:

\(A\) 买来的用具的短直角边长度为 \(i cm\),长直角边长 \(j cm\),厚度为 $ 1cm$。到货后,小 \(A\) 发现他需要自己给容器装水(一共要装 \(i^2+j^2cm^3\) 液体),于是又需要买一些蓝色的液体。

他发现商店里卖的蓝色液体只有 \(m cm^3\) 一瓶的,本着不浪费的原则,他想知道是否存在一个数 \(k\),使小 \(A\)\(k\) 瓶的容量为 \(m cm^3\)
瓶的蓝色液体可以正好装满用具。

这个问题对于小 \(A\) 来说太简单了,所以他想知道有多少个教学用具满足下面条件:

  • 其短直角边长度和长直角边长度都是整数。
  • 短直角边长度 \(\le\) 长直角边长度,且长直角边长 \(\le n cm\)
  • 存在一个数 \(k\),使小 \(A\)\(k\) 瓶的容量为 \(m cm^3/\text{瓶}\) 的蓝色液体可以正好装满用具。

输入格式

一共一行两个整数,分别表示 \(n,m\)

输出格式

一行一个整数,表示答案。

样例数据

【样例 \(1\) 输入】

6 3

【样例 \(1\) 输出】

3

【样例 \(1\) 解释】
合法的教学用具为 \((3,3),(3,6),(6,6)\),其中 \((x,y)\) 表示短直角边为 \(x\) 长直角边为 \(y\) 的教学用具。
【样例 \(2\) 输入】

949 216

【样例 \(2\) 输出】

702

数据范围

对于所有数据 \(n\le10^9,m\le10^6\)

测试点 数据范围
\(1-4\) \(n,m\le30\)
\(5-8\) \(n\le1000\)
\(9-10\) \(m=1\)
\(11-12\) \(m=2\)
\(13-15\) \(n\le10^6,m\le1000\)
\(16-18\) \(m\le1000\)
\(19-20\) 无限制

题解

  • 考点:数论,简单计数
  • 难度:CSP-J T3

我们可以依次考虑每一个 \(i^2\mod m\) 是多少,然后记 \(f_i\)\(i^2\mod m=j\) 的这样的 \(i\) 的个数。

那么如果不考虑 \(i\mod m=j\),答案就是 \(\sum_{i=0}^{m-1}f_if_{m-1}\mod m\)

如何处理 \(i\le j\),那么我们可以把 \(i=j\) 的情况再算一次之后,把整个答案除以 \(2\)

如何计算 \(2i^2\mod m=0\) 的个数?实际上只有当 \(i^2\mod m=0\)\(\frac{m}{2}\) 才可以,那么方案数就是 \(f_0+f{\frac{n}{2}}\)

随后可以发现难点在于得到 \(f_i\),其实对于所有 \(i\mod m\) 相同的 \(i\),其 \(i^2\mod m\) 的值也相同。

而满足 \(i\mod m=j\)\(i\) 的个数是好处理的。

所以就可以 \(O(m)\) 的时间复杂度内解决此题。

代码

#include <bits/stdc++.h>
#define int long long

using namespace std;

const int kMaxN = 1e6 + 10;

int f[kMaxN], n, m, ans;

signed main() {
  freopen("pythagorean.in", "r", stdin);
  freopen("pythagorean.out", "w", stdout);
  ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  cin >> n >> m;
  for (int i = 0; i < m; i++) {
    f[i * i % m] += n / m, f[i * i % m] += ((n % m >= i) && (i ? 1 : 0));
  }
  for (int i = 0; i < m; i++) {
    int j = (m - i) % m;
    if (i == j) {
      ans += (f[i] + 1) * f[i];
    } else {
      ans += f[i] * f[j];
    }
  }
  cout << ans / 2 << '\n';
  return 0;
}
posted @ 2024-09-23 12:01  小熊涛涛  阅读(25)  评论(0编辑  收藏  举报