题意:给两个数a,b,a为某个长方形的面积(不能为正方形),求长和宽都不小于b且面积为a的长方形的个数。
- 1 ≤ b ≤ a ≤ 1e12
- 多组输入T<=4000
题解:唯一分解定理求a的因数个数,然后除2取整(懂的都懂,另外如果存在sqrt(a)*sqrt(a)=a,也是这样,不用特意考虑,所以count部分完全模板)。然后cnt暴力计数小于b的数是否a%i==0(这里注意可能3*4=a=12,b=5,会记录两次,但是不用考虑,可以直接特判b*b>=a 返回答案0,懂的都懂)。
答案为count(x)/2-cnt。
复杂度最高O(4e9)勉强过了(感觉数论都是这种最高1e9+,但是一般都不会达到。忽悠人?建议循环变量外置)。
ps:听别人说唯一分解定理之后可以快速求出这个数的所有因数???反正网上没人写这个代码的样子。
代码:
#include <bits/stdc++.h>
#define int long long
#define read(x) scanf("%lld", &x)
#define print(a, c) printf("%lld%c", a, c)
#define dbg(x) cout << #x << "===" << x << endl
using namespace std;
const int N = 1e6 + 10;
int a, b;
int prime[N], vis[N];
void init(int n) {
for (int i = 2; i <= n; i++) {
if (vis[i]) continue; //非素数
prime[++prime[0]] = i;
for (int j = i + i; j <= n; j += i) vis[j] = 1;
}
}
//先素数筛算是一个优化,大概能优化一个数量级吧
int count(int x) {
int res = 1, i, a;
//从1开始,prime[0]为素数个数
//不能等于,因为不能为正方形
//不过,尽管大胆一点去分解,若存在sqrt(x)*sqrt(x)=x,无非因数个数为奇数
for (i = 1; prime[i] * prime[i] <= x && i <= prime[0]; i++) {
a = 0;
while (x % prime[i] == 0) a++, x /= prime[i];
res *= (a + 1); //很多*1
}
if (x > 1) res *= (1 + 1);
return res;
}
signed main() {
init(N - 1);
int T;
read(T);
int ans, cnt, i;
for (int _ = 1; _ <= T; _++) {
read(a), read(b);
ans = 0;
if (b * b >= a)
ans = 0;
else {
cnt = 0, i;
for (i = 1; i < b; i++)
if (a % i == 0) cnt++;
ans = count(a) / 2 - cnt;
}
printf("Case %lld: %lld\n", _, ans);
}
return 0;
}
补充:蜜汁复杂度,如果严格按照要求的最大限制,那么上面的做法和下面暴力差不多吧。这题应该只是卡了下面这种做法。事实上应该可以互补,比如b太大就下面这种,太小就上面这种。感觉也优化不到什么emm