题解 玄学题

传送门

考场上三次迭代搞出一个\(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\)相乘时,分两种情况

  1. \(p[i]\)中不含\(pri_j\)这个因子: \(p[i*pri_j] = p[i]*pri_j\)
  2. \(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;
}
posted @ 2021-07-13 17:01  Administrator-09  阅读(18)  评论(0编辑  收藏  举报