1.题目链接。问题很简洁,就是求一下区间[l,r]里的每一个i,i的k次方因子个数之和。

【HDU6069】区间素数筛+因子个数

首先我们知道d(i)=(a1+1)*(a2+1)...(ak+1),其中a1,a2...ak是对i进行素因子分解之后每个素因子的指数。这个结论很好证明,就简单的排列组合一下就好。那么对于:i^k.唯一的变化就是素因子分解之后ai变成了ai*k.那么式子形式还是不变的:d(i^k)=(a1*k+1)...(ak*k+1).式子推出来了,然后事情并没有完成。因为数据很大,但是区间不大,所以我们直接筛整个区间的素数,然后分解素因子。做这个操作之前我们首先需要把预处理前1e6之内的素数,然后使用这些素数进行分解区间的每一个数据。最后统计答案即可。这里有一种离散化的思想,我们可定是需要记录[l,r]整个区间的数据的,但是我们没有办法直接记录,所以就做一个相对的变换,所有数的位置相对与l来计算。这样1e6的数组存下它就完事了,然后统计这个数组种每个元素的贡献,先把他们分解,计算每个数据的贡献,最后统计。但是在最后统计的时候需要注意,判断是不是分解完了,如果数据剩余的是1,那么表示刚好分解完,如果不是1,说明还剩下一个因子,把它也要计算上去。完美!

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 10;
const int mod = 998244353;
#define ll long long
#pragma warning(disable:4996)
int prime[MAXN], vis[MAXN], tot;
ll sum[MAXN], gel[MAXN];
void get_prime()
{
	for (int i = 2; i < MAXN; i++)
	{
		if (!vis[i])
		{
			prime[tot++] = i;
			for (int j = 2; j*i < MAXN; j++)
			{
				vis[i*j] = 1;
			}
		}
	}
}
int main()
{
	get_prime();
	ll l, r;
	int t, k;
	scanf("%d", &t);
	while (t--)
	{
		scanf("%lld%lld%d", &l, &r, &k);
		for (int i = 0; i <= r - l; i++)
		{
			sum[i] = 1;
			gel[i] = i + l;
		}
		for (int i = 0; i < tot; i++)
		{
			ll a = (l + prime[i] - 1) / prime[i] * prime[i];
			for (ll j = a; j <= r; j+=prime[i])
			{
				ll cnt = 0;
				while (gel[j - l] % prime[i] == 0)
				{
					cnt++;
					gel[j - l] /= prime[i];
				}
				sum[j - l] = sum[j - l] * (cnt*k + 1 % mod);
				sum[j - l] %= mod;
			}
		}
		ll ans = 0;
		for (int i = 0; i <= r - l; i++)
		{
			if (gel[i] != 1)
				sum[i] = sum[i] * (k + 1);
			ans += sum[i];
			ans %= mod;
		}
		cout << ans << endl;
	}
}

 

相关文章:

  • 2021-12-16
  • 2022-12-23
  • 2021-05-22
  • 2021-09-16
  • 2022-12-23
  • 2021-06-22
  • 2021-07-13
  • 2021-10-02
猜你喜欢
  • 2021-05-22
  • 2021-12-15
  • 2022-12-23
  • 2021-11-25
  • 2022-03-04
  • 2021-05-30
  • 2021-08-10
相关资源
相似解决方案