您的位置:首页 > 其它

Hdu 6069 - Counting Divisors(区间筛质因子)

2017-08-04 15:52 309 查看
题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=6069

题目大意:

给定区间[l,r]和k,d(i)=∑d=1,d|nn1求式子∑i=lrd(ik)的值,结果对998244353取模

分析:

区间长度为1e6,数据有10组以上,暴力分解整个区间的话,每个数的分解至多是logn级别的,而基于Miller_Robin的质因数分解polard_rho也只是O(n14)级别的,远远达不到要求,所以不能从对每个数分解质因数上想,而是试着用[2,r√]内的所有质因子去筛[l,r]区间内的数,最后在除尽了这些因子后的数,要么是1,要么是一个大的质因子,且次数至多为1,因为如果大于sqrtr的因子次数大于1,这个数的大小就会大于r,产生矛盾

代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const ll mod = 998244353;
const int maxn = 1e6+100;

ll l,r,k;
int len;
bool isprime[maxn+200];
int prime[maxn];

ll divi[maxn];
ll cnt[maxn];

void init()
{
for (int i =2 ; i <= maxn; i ++)
{
if (!isprime[i])
{
prime[++prime[0]] = i;
for (int j = i +i ; j <= maxn ; j+= i)
isprime[j] = true;
}
}
}

void solve()
{
int st;
for (int i = 1 ; prime[i]<= r/prime[i] && i<= prime[0] ; i ++)
{
//printf("i = %d\n",prime[i]);
if (l%prime[i]==0)
st = 1;
else
st = 1 + (prime[i]-l%prime[i]);
for (int j = st ; j <= len ; j +=prime[i])
{
int ct = 0;
while (divi[j]%prime[i]==0)
{
divi[j]/=prime[i];
ct++;
}
cnt[j]*=(ct*k+1);
if (cnt[j]>=mod)
cnt[j] %= mod;
}
}
ll ans = 0;
for (int i =1 ; i <= len ; i ++)
{
if (divi[i]!=1)
cnt[i] = cnt[i] * (k+1)%mod;
//printf("divi[%d] = %lld\n",i,divi[i]);
ans += cnt[i];
if (ans>=mod)
ans %= mod;
}
printf("%lld\n",ans);
}

int main()
{
init();
//printf("prime[0] = %d\n",prime[0]);
int T;
scanf("%d",&T);
while (T--)
{
scanf("%lld%lld%lld",&l,&r,&k);
len = (int)(r- l +1);
for (int i = 1 ; i <= len ; i ++)
{
divi[i] = l + i -1;
cnt[i] = 1;
}

solve();

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: