hdu6069 區間篩 2017多校第四場1003

題意
設d(n)爲n的因子的個數,讓你求sumri=ld(ik)%998244353

題解
這題主要用到了一些定理和歐拉篩法。
首先我們應該思考對於d(n)怎麼能簡單計算出來。
這裏有一個定理,由唯一分解定理知n=pk11pk22... ,其中pi 爲素數,而d(n)=(k1+1)(k2+1)...
這時我們就能簡單的計算出d(n),同理可以推出d(nk)=(kk1+1)(kk2+1)...
現在對於我們的問題就是怎麼快速的將區間[l,r]中的數唯一分解出來,如果直接l-r遍歷分解的話會超時。那麼怎麼快速求呢?
這裏要知道d(n)是一個積性函數,而積性函數有一個性質就是f(a*b)=f(a)*f(b),這裏gcd(a,b)=1即a,b互質。而這裏d(n)中對於每一個因子pi 來說都是互質的,所以對於每個質數來說,其對答案的貢獻都是互不影響的。所以我們對區間[l,r]直接對於每個質數計算貢獻而不是用區間中數一個個去分解即可。
最後還有一個問題就是l和r的範圍爲1012 ,那麼這裏按理說應該篩出1012 以內的所有質數(比賽時我就是因爲這個放棄的,不過我上面那個對質數算貢獻也沒想到,好菜QAQ),但是這樣會超時。這裏要知道一個知識,就是對於n以內的數,n -n中的數沒有被1-n 中素數篩出來的數一定是素數。(可以用反證法證明)所以對於這題其實我們只需要篩出106 以內所有素數即可。

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long ll;

const int maxn = 1e6+5;
const int mod = 998244353;
//num爲10^6以內素數的個數,prime[]儲存這些素數
ll l,r,k,prime[maxn],num,sz[maxn],res[maxn];
bool isprime[maxn];

void get_Prime() //歐拉篩法
{
    num = 0;
    memset(isprime,true,sizeof(isprime));
    for(int i=2;i<maxn;i++)
    {
        if(isprime[i]) prime[num++] = i;
        for(int j=0;j<num&&prime[j]*i<maxn;j++)
        {
            isprime[i*prime[j]] = false;
            if(i%prime[j]==0) break;
        }
    }
}

int main()
{
    int t;
    get_Prime();
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld%lld%lld",&l,&r,&k);
        for(ll i=l;i<=r;i++)
        {
            sz[i-l] = i;//儲存分解的數
            res[i-l] = 1;//儲存區間中數的d()值
        }
        //對於每個素數對區間開始分解
        for(int i=0;i<num&&prime[i]*prime[i]<=r;i++)
        {
            //從區間中該素數的最小倍數開始分解
            for(ll j=prime[i]*(l/prime[i]);j<=r;j+=prime[i])
            {
                if(j<l) continue;
                ll cnt=0;
                while(sz[j-l]%prime[i]==0)
                {
                    cnt++;
                    sz[j-l]/=prime[i];
                }
                res[j-l] = (res[j-l]*(cnt*k+1))%mod;
            }
        }
        ll ans=0;
        for(ll i=l;i<=r;i++)
        {
            //如果分解剩下的數大於1那麼就一定是一個大於10^6的素數
            if(sz[i-l]>1) res[i-l] = (res[i-l]*(k+1))%mod;
            ans = (ans+res[i-l])%mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
發佈了82 篇原創文章 · 獲贊 37 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章