题解 玄学题
考场上三次迭代搞出一个\(O(nm)\)的做法拿了60pts
首先打表可知\(d(x)\)在且仅在\(x\)为完全平方数时为奇
于是问题被转化为求\(i*j\)中完全平方数的个数
然而不会求,于是自闭
根据题解发现对于一个 \(i*j=k^2\) 一定有 \(i=p*k_1^2, j=p*k_2^2\),\(p\)中不含完全平方因子
所以问题可以被转化为求合法的\(p\)的个数
这个东西可以用线性筛
- 是不是所有完全积性函数都能用线性筛处理啊?
当一个\(i\)和一个\(pri_j\)相乘时,分两种情况
- \(p[i]\)中不含\(pri_j\)这个因子: \(p[i*pri_j] = p[i]*pri_j\)
- \(p[i]\)中包含\(pri_j\)这个因子: 直接相乘就有完全平方因子了,所以从\(p[i]\)里除掉一个\(pri_j\),\(p[i*pri_j]=p[i]/pri_j\)
有\(p[\ ]\)数组了,每个\(i\)对答案的贡献就是对于每个\(j=p*r^2\),合法\(r^2\)的个数,即\(\sqrt \frac{m}{p[i]}\)
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 10001000
#define ll long long
#define ld long double
#define usd unsigned
#define ull unsigned long long
#define int long long
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
char buf[1<<21], *p1=buf, *p2=buf;
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
ll n, m;
#if 0
namespace force1{
int lim, ans;
int cnt2[100000100];
void solve() {
lim=n*m;
for (int i=1,cnt,t; i<=lim; ++i) {
//cout<<i<<endl;
cnt=1; t=i;
for (int j=2; j*2<=i; ++j) {
if (t%j==0) {
++cnt;
//while (t%j==0) t/=j;
}
}
if (t>1) ++cnt;
cnt2[i]=cnt;
}
for (int i=1,cnt; i<=n; ++i) {
cnt=0;
for (int j=1; j<=m; ++j) cnt+=cnt2[i*j], cnt%=2;
if (cnt%2==0) ++ans;
else --ans;
//cout<<"ans: "<<ans<<endl;
}
//for (int i=1; i<=lim; ++i) cout<<cnt2[i]<<' '; cout<<endl;
cout<<ans<<endl;
exit(0);
}
}
#endif
#if 0
namespace force2{
int lim, ans;
int cnt2[100000100];
void solve() {
lim=n*m;
for (int i=1,cnt,t; i<=lim; ++i) {
for (int j=1; i*j<=lim; ++j) ++cnt2[i*j];
}
for (int i=1,cnt; i<=n; ++i) {
cnt=0;
for (int j=1; j<=m; ++j) {
cnt+=cnt2[i*j], cnt%=2;
//if (cnt2[i*j]%2==1) cout<<i<<' '<<j<<endl;
}
if (cnt%2==0) ++ans;
else --ans;
//cout<<"ans: "<<ans<<endl;
}
//for (int i=1; i<=lim; ++i) cout<<setw(2)<<i<<' '; cout<<endl;
//for (int i=1; i<=lim; ++i) cout<<setw(2)<<cnt2[i]%2<<' '; cout<<endl;
//for (int i=1; i<=lim; ++i) cout<<setw(2)<<cnt2[i]<<' '; cout<<endl;
cout<<ans<<endl;
exit(0);
}
}
#endif
namespace force3{
int lim, ans;
bool vis[100000100];
void solve() {
lim=n*m;
for (int i=1; i*i<=lim; ++i) vis[i*i]=1;
for (int i=1,cnt; i<=n; ++i) {
cnt=0;
for (int j=1; j<=m; ++j) cnt+=vis[i*j];
if (cnt%2==0) ++ans;
else --ans;
//cout<<"ans: "<<ans<<endl;
}
printf("%lld\n", ans);
exit(0);
}
}
namespace task1{
ll ans, lim;
void solve() {
lim=n*m;
for (int i=1,cnt; i<=n; ++i) {
cnt=0;
for (int j=1; j*j<=lim; ++j)
if (j*j%i==0 && (j*j/i<=m)) ++cnt;
if (cnt%2==0) ++ans;
else --ans;
}
printf("%lld\n", ans);
exit(0);
}
}
namespace task{
ll ans, p[N], pri[N], pcnt;
bool npri[N];
void solve() {
npri[0]=npri[1]=1;
p[1]=1; p[2]=2; p[3]=3;
for (int i=2; i<=n; ++i) {
if (!npri[i]) pri[++pcnt]=i, p[i]=i;
for (int j=1; j<=pcnt&&i*pri[j]<=n; ++j) {
npri[i*pri[j]]=1;
if (p[i]%pri[j]) p[i*pri[j]]=p[i]*pri[j];
else p[i*pri[j]]=p[i]/pri[j];
if (!(i%pri[j])) break;
}
}
//for (int i=1; i<=n; ++i) cout<<p[i]<<' '; cout<<endl;
for (int i=1; i<=n; ++i) ans+=(int)floor(sqrt(double(m)/p[i]))%2?-1:1;
printf("%lld\n", ans);
exit(0);
}
}
signed main()
{
#ifdef DEBUG
freopen("1.in", "r", stdin);
#endif
n=read(); m=read();
//if (m>=(ll)(1e6)) task1::solve();
//else force3::solve();
task::solve();
return 0;
}