DIVCNT2 - Counting Divisors (square) 

DIVCNT3 - Counting Divisors (cube) 

杜教筛

[学习笔记]杜教筛

(其实不算是杜教筛,类似杜教筛的复杂度分析而已)

你要大力推式子:

把约数个数代换了

把2^质因子个数 代换了

构造出卷积,然后大于n^(2/3)还要搞出约数个数的式子和无完全平方数的个数的容斥。。。

。。。。

然后恭喜你,spoj上过不去。。。

bzoj能过:

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define ul unsigned long long
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void rd(int &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
namespace Miracle{
const int N=998630;
ll n;
ul miu[N],sig[N],sq[N];
bool vis[N];
int divcnt[N],pri[N+5],tot;
ll a[200005];
ll up;
void sieve(ll n){
    miu[1]=1;sig[1]=1;
    for(reg i=2;i<=n;++i){
        if(!vis[i]){
            pri[++tot]=i;
            miu[i]=-1;
            sig[i]=2;
            divcnt[i]=1;
        }
        for(reg j=1;j<=tot;++j){
            if(pri[j]*i>n) break;
            vis[pri[j]*i]=1;
            if(i%pri[j]==0){
                divcnt[i*pri[j]]=divcnt[i]+1;
                miu[i*pri[j]]=0;
                sig[i*pri[j]]=sig[i]/(divcnt[i]+1)*(divcnt[i]+2);
                break;
            }
            divcnt[i*pri[j]]=1;
            miu[i*pri[j]]=-miu[i];
            sig[i*pri[j]]=sig[i]*sig[pri[j]];
        }
    }
    sq[1]=1;
    for(reg i=2;i<=n;++i) {
        sq[i]=miu[i]*miu[i];
        sq[i]+=sq[i-1];
         
        sig[i]+=sig[i-1];
    }
}
ul M(ll n){
    if(n<=up) return sq[n];
    ul ret=0;
    for(reg i=1;(ll)i*i<=n;++i){
        ret=ret+miu[i]*(n/(i*i));
    }
    //cout<<" M "<<ret<<endl;
    return ret;
     
}
ul S(ll n){
    if(n<=up) return sig[n];
    ul ret=0;
    for(ll i=1,x=0;i<=n;i=x+1){
        x=(n/(n/i));
        ret=ret+(x-i+1)*(n/i);
    }
//  cout<<" S "<<ret<<endl;
    return ret;
     
}
ul solve(ll n){
    ul ret=0;
    for(ll i=1,x=0;i<=n;i=x+1){
        x=(n/(n/i));
        ret=ret+(M(x)-M(i-1))*S(n/i);
    //  cout<<"["<<i<<","<<x<<"] : "<<ret<<endl;
    }
    return ret;
}
int main(){
    int t;
    rd(t);
    ll mx=0;
    for(reg i=1;i<=t;++i) scanf("%lld",&a[i]),mx=max(mx,a[i]);
    if(mx<=N-5){
        up=mx;
        sieve(up);
    }else{
        up=N-5;
        sieve(up);
    }
    for(reg i=1;i<=t;++i){
        printf("%llu\n",solve(a[i]));
    }
    return 0;
}
 
}
signed main(){
    Miracle::main();
    return 0;
}
 
/*
   Author: *Miracle*
   Date: 2019/3/6 21:18:05
*/
View Code

相关文章:

  • 2021-09-09
  • 2021-10-07
  • 2021-12-15
  • 2022-01-20
  • 2022-12-23
  • 2021-09-17
  • 2022-12-23
  • 2021-07-13
猜你喜欢
  • 2022-12-23
  • 2021-12-09
  • 2022-12-23
  • 2022-12-23
  • 2021-12-03
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案