J - Sum(南京预选赛周末训练赛)补题

本文介绍了一种使用欧拉筛法计算无平方整数的组合数量的方法。通过筛选素数并根据特定规则更新组合数量,实现了对任意整数n的a*b=n的无平方因数分解组合的有效计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
题意:(square-free integer )无平方整数是除了1以外不被其它整数的平方除的数.
一个数n = ab,问你有多少个a,b的组合,a,b都是无平方整数,用f(n)表示,让你求在这里插入图片描述
思路:首先需明白欧拉筛,利用欧拉筛来求解每个的f(i)。
①欧拉筛首先是确定是否为素数,如果为素数,那么f(i)肯定就只有两个((1,i),(i,1))。
②然后欧拉筛就利用素数来筛去非素数,筛的每一步都是筛掉
i * primes[j], 那么这里就对 i*primes[j] 进行判断。
分为以下情况
如果i%primes[j] != 0 那么i不是priems[j]的倍数,那么dp[i*priems[j]] = dp[i] * dp[primes[j]] ;不用考虑因数的限制,就是它们的组合。
如果i%primes[j] ==0 ** ,那么这时候就需要考虑i里面有几个priems[j]了,
如果
i%(primes[j] * primes[j])==0**,那么i * prime[j]里面肯定有大于等于三个的primes[j],所以无论怎么分给a和b,都不满足条件,于是可以得出
dp[i] = 0;
但如果知识 i%primes[j] ==0 那么i * primes[j]里面只有两个primes[j],那么这时a和b中就各分一个primes[j],其实就是求dp[i/primes[j]]的个数了。
dp[i] = dp[i/primes[j]];

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e7 + 5;
typedef long long ll;
ll dp[maxn];
bool vis[maxn];
ll primes[maxn];
ll cnt;
void solve_num(){
    //memset(dp,1,sizeof(dp));错误了,memset是依靠二进制进行初始化的所以只能赋值为0
     dp[1] = 1;
	for(ll i = 2 ;i < maxn;i++){
		if(!vis[i]){
			primes[cnt ++] = i;
			dp[i] = 2; 
		}
		for(ll j = 0 ; i * primes[j] < maxn ; j++){
			vis[i * primes[j]] = true;
			
			if(i % primes[j] != 0){
				dp[i*primes[j]] = dp[i] * dp[primes[j]];
			}
			else{
				if(i % (primes[j]*primes[j]) == 0 ){ 
					dp[i * primes[j]] = 0; 
				} 
				else{
					dp[i * primes[j]] =  dp[i/primes[j]];
				}
				break;
			}
		} 
	}
	for(int i =1;i<maxn;i++){
		dp[i] += dp[i-1];
	}
}
int main(){
	solve_num();
	ll t,n;
	cin>>t;
	ll ans;
	while(t--){
		ans = 0;
		cin>>n;
	   cout<<dp[n]<<endl;
	}
	return 0;
}

(emmmm,欧拉筛还能这样用的,第一次遇见)
如果有什么错的话,请提出来嘿嘿嘿嘿

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值