AtCoder-abc254_d Together Square
Together Square
唯一分解定理 + 递推
如果从 \(n - 1\) 递推到 \(n\) 的话,只要考虑任意的组合 \((i,n)\) \(i < n\) 的所有个数的 2 倍,再加上一个 \((n, n)\) 就可以了
接下来就考虑能不能快速求出 \((i, n)\) 满足条件的个数
如果一个数是平方数,则质因数分解出来的频率均为偶数,我们可以根据这个要求要计算
考虑质因数分解,如果 \(n\) 分解出来的质因数的频率是偶数次,则无影响,如果是奇数次,则会要求 i 的质因数分解中,该质数出现的频率为奇数
我们先算出所有 \(i\) 必须带有的质数的乘积,然后剩下的就是求平方数的次数了,显然有:要求小于等于 x 的平方数的个数,答案为 \(\lfloor \sqrt{x} \rfloor\)
因为 i 的范围是 \(1 \le i < n\),且 \(i = x * k^2\),x 为 i 必须带有的质数乘积,\(k^2\) 表示平方数,则其数量的计算就为 \(\lfloor \sqrt{\frac{n - 1}{x}} \rfloor\)
质因数分解的话,直接用欧拉筛的方式预处理所有合数的其中一个因数,然后不断往下除就是了
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
int num[maxn], pre[maxn];
ll dp[maxn];
void init(int n)
{
pre[1] = 1;
for(int i=2; i<=n; i++)
{
if(pre[i]) continue;
for(int j=i; j<=n; j+=i)
pre[j] = i;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
init(n);
for(int i=1; i<=n; i++)
{
ll temp = 0;
if(pre[i] != i)
{
ll x = i, ans = 1;
while(pre[x] != x)
{
ll now = pre[x], way = 0;
while(pre[x] == now)
{
x /= pre[x];
way++;
}
if(way & 1)
ans *= now;
}
ans *= pre[x];
temp = sqrt((i - 1) / ans);
}
dp[i] = dp[i-1] + temp * 2 + 1;
}
cout << dp[n] << endl;
return 0;
}

浙公网安备 33010602011771号