BZOJ.3944.Sum(杜教筛)

题目链接

又写个模板题用了半晚上。。

卡常写法

还非常短。。

//35332 kb  7608 ms
//跟Kelin dalao学一波卡常。怎么还是很慢QAQ
//phi[]要longlong!
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const int N=2e6;

int cnt,Max,P[N>>3];
LL phi[N],mu[N],sum[20005][2];
bool Not_p[N],vis[20005];

void Make_Table()
{
    mu[1]=phi[1]=1;
    for(int i=2; i<N; ++i)
    {
        if(!Not_p[i]) P[++cnt]=i, mu[i]=-1, phi[i]=i-1;
        for(int j=1,x; j<=cnt&&(x=i*P[j])<N; ++j)
        {
            Not_p[x]=1;
            if(i%P[j]) mu[x]=-mu[i], phi[x]=phi[i]*(P[j]-1);
            else {mu[x]=0, phi[x]=phi[i]*P[j]; break;}
        }
    }
    for(int i=2; i<N; ++i) mu[i]+=mu[i-1],phi[i]+=phi[i-1];
}
inline LL Get_phi(int n){
    return n<N?phi[n]:sum[Max/n][0];
}
inline LL Get_mu(int n){
    return n<N?mu[n]:sum[Max/n][1];
}
void Calc(int n)
{
    if(n<N) return;
    if(vis[Max/n]) return;
    int t=Max/n;
    vis[t]=1, sum[t][0]=((LL)n+1)*n>>1, sum[t][1]=1;//这只在前面转longlong不行!+1必须也longlong。
    for(LL nxt,i=2; i<=n; i=nxt+1){
        nxt=n/(n/i), Calc(n/i);
        sum[t][0]-=Get_phi(n/i)*(nxt-i+1), sum[t][1]-=Get_mu(n/i)*(nxt-i+1);
    }
}

int main()
{
    Make_Table();
    int T; scanf("%d",&T);
    while(T--){
        memset(vis,0,sizeof vis);
        scanf("%d",&Max);
        if(Max<N) printf("%lld %lld\n",phi[Max],mu[Max]);//mu[]如果是int就不要用%lld。
        else Calc(Max),printf("%lld %lld\n",sum[1][0],sum[1][1]);
    }
    return 0;
}

朴素写法

//
//phi[]要longlong!
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const int N=5e6;

int cnt,Max,P[N>>3],mu[N];
LL phi[N],sum[20005][2];
bool Not_p[N],vis[20005][2];

void Make_Table()
{
    mu[1]=phi[1]=1;
    for(int i=2; i<N; ++i)
    {
        if(!Not_p[i]) P[++cnt]=i, mu[i]=-1, phi[i]=i-1;
        for(int j=1; j<=cnt&&i*P[j]<N; ++j)
        {
            Not_p[i*P[j]]=1;
            if(i%P[j]) mu[i*P[j]]=-mu[i], phi[i*P[j]]=phi[i]*(P[j]-1);
            else {mu[i*P[j]]=0, phi[i*P[j]]=phi[i]*P[j]; break;}
        }
    }
    for(int i=2; i<N; ++i) mu[i]+=mu[i-1],phi[i]+=phi[i-1];
}
LL Calc_p(LL n)//这的n为什么必须要开longlong(2147483647)?因为下边。。
{
    if(n<N) return phi[n];
    if(vis[Max/n][0]) return sum[Max/n][0];
    vis[Max/n][0]=1;
    LL res=1ll*n*((LL)n+1)>>1;//这只在前面转longlong不行!+1必须也有。
    for(LL nxt,i=2; i<=n; i=nxt+1)//nxt+1!可能爆int?
        nxt=n/(n/i), res-=Calc_p(n/i)*(nxt-i+1);
    return sum[Max/n][0]=res;
}
LL Calc_m(int n)
{
    if(n<N) return mu[n];
    if(vis[Max/n][1]) return sum[Max/n][1];
    vis[Max/n][1]=1;
    LL res=1;
    for(LL nxt,i=2; i<=n; i=nxt+1)
        nxt=n/(n/i), res-=Calc_m(n/i)*(nxt-i+1);
    return sum[Max/n][1]=res;
}

int main()
{
    Make_Table();
    int T,n; scanf("%d",&T);
    while(T--){
        memset(vis,0,sizeof vis);
        scanf("%d",&Max),printf("%lld %lld\n",Calc_p(Max),Calc_m(Max));
    }
    return 0;
}

map

洛谷上还行吧。。BZOJ成功T掉。

//phi[]要longlong!
#include <map>
#include <cstdio>
#include <algorithm>
typedef long long LL;
const int N=6e6;

int cnt,P[N>>3],mu[N];
LL phi[N];
bool Not_p[N];
std::map<int,LL> mp[2];
std::map<int,LL>::iterator it;

void Make_Table()
{
    mu[1]=phi[1]=1;
    for(int i=2; i<N; ++i)
    {
        if(!Not_p[i]) P[++cnt]=i, mu[i]=-1, phi[i]=i-1;
        for(int j=1; j<=cnt&&i*P[j]<N; ++j)
        {
            Not_p[i*P[j]]=1;
            if(i%P[j]) mu[i*P[j]]=-mu[i], phi[i*P[j]]=phi[i]*(P[j]-1);
            else {mu[i*P[j]]=0, phi[i*P[j]]=phi[i]*P[j]; break;}
        }
    }
    for(int i=2; i<N; ++i) mu[i]+=mu[i-1],phi[i]+=phi[i-1];
}
LL Calc_p(LL n)//这的n为什么必须要开longlong(2147483647)?
{
    if(n<N) return phi[n];
    if((it=mp[0].find(n))!=mp[0].end()) return it->second;
    LL res=n*(n+1)>>1;
//  if(n&1) res=(n+1)/2*n;
//  else res=n/2*(n+1);
    for(LL nxt,i=2; i<=n; i=nxt+1)//nxt+1!可能爆int?
        nxt=n/(n/i), res-=Calc_p(n/i)*(nxt-i+1);
    return mp[0][n]=res;
}
LL Calc_m(int n)
{
    if(n<N) return mu[n];
    if((it=mp[1].find(n))!=mp[1].end()) return it->second;
    LL res=1;
    for(LL nxt,i=2; i<=n; i=nxt+1)
        nxt=n/(n/i), res-=Calc_m(n/i)*(nxt-i+1);
    return mp[1][n]=res;
}

int main()
{
    Make_Table();
    int T,n; scanf("%d",&T);
    while(T--)
        scanf("%d",&n),printf("%lld %lld\n",Calc_p(n),Calc_m(n));
    return 0;
}

原文地址:https://www.cnblogs.com/SovietPower/p/8710976.html

时间: 2024-07-30 22:16:04

BZOJ.3944.Sum(杜教筛)的相关文章

bzoj 3944 Sum —— 杜教筛

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3944 杜教筛入门题! 看博客:https://www.cnblogs.com/zjp-shadow/p/8491542.html 写法模仿其他博客的,但很慢啊... 代码如下: #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<ma

3944: Sum[杜教筛]

3944: Sum Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3471  Solved: 946[Submit][Status][Discuss] Description Input 一共T+1行 第1行为数据组数T(T<=10) 第2~T+1行每行一个非负整数N,代表一组询问 Output 一共T行,每行两个用空格分隔的数ans1,ans2 Sample Input 6 1 2 8 13 30 2333 Sample Output 1 1

洛谷P4213 Sum(杜教筛)

题目描述 给定一个正整数N(N\le2^{31}-1)N(N≤231−1) 求ans_1=\sum_{i=1}^n\phi(i),ans_2=\sum_{i=1}^n \mu(i)ans1?=∑i=1n??(i),ans2?=∑i=1n?μ(i) 输入输出格式 输入格式: 一共T+1行 第1行为数据组数T(T<=10) 第2~T+1行每行一个非负整数N,代表一组询问 输出格式: 一共T行,每行两个用空格分隔的数ans1,ans2 输入输出样例 输入样例#1: 复制 6 1 2 8 13 30 2

●杜教筛入门(BZOJ 3944 Sum)

入门杜教筛啦. http://blog.csdn.net/skywalkert/article/details/50500009(好文!) 可以在$O(N^{\frac{2}{3}})或O(N^{\frac{3}{4}})$的复杂度内解决求某些数论函数f(n)(或f的前缀和S(n)$)的值. 先来看看原理是什么.(接下来推导如何求数论函数f(n)的前缀和S(n)) 现在有两个数论函数$f( )和g( )$ (同时定义f的前缀和函数$S(n)=\sum_{i=1}^{n}f(i)$) 有狄利克雷乘

3944: Sum(杜教筛)

3944: Sum Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 4930  Solved: 1313[Submit][Status][Discuss] Description Input 一共T+1行 第1行为数据组数T(T<=10) 第2~T+1行每行一个非负整数N,代表一组询问 Output 一共T行,每行两个用空格分隔的数ans1,ans2 Sample Input 6 1 2 8 13 30 2333 Sample Output 1 1

【bzoj 4176】 Lucas的数论 莫比乌斯反演(杜教筛)

Description 去年的Lucas非常喜欢数论题,但是一年以后的Lucas却不那么喜欢了. 在整理以前的试题时,发现了这样一道题目“求Sigma(f(i)),其中1<=i<=N”,其中 表示i的约数个数.他现在长大了,题目也变难了. 求如下表达式的值: 一行一个整数ans,表示答案模1000000007的值. Sample Input 2 Sample Output 8 HINT 对于100%的数据n <= 10^9. 题解: 解锁新技能:杜教筛. 再复习一下: 若$F(n)=\s

bzoj 4916 神犇和蒟蒻 杜教筛

第一题结合莫比乌斯函数定义,值恒为1. 第二题,phi(i^2) = phi(i) * i,根据欧拉函数的定义式能推出来,每个质因子的指数都增加一倍,都提出来一份,就是原先的phi(i)*i.然后还是跟g(x)卷一下,杜教筛即可. 1 #include <cstdio> 2 #include <map> 3 #include <cmath> 4 using namespace std; 5 typedef long long ll; 6 const int MAXN =

P4213 【模板】杜教筛(Sum)

\(\color{#0066ff}{题 目 描 述}\) 给定一个正整数\(N(N\le2^{31}-1)\) 求 \(\begin{aligned} ans_1=\sum_{i=1}^n\varphi(i) \end{aligned}\) \(\begin{aligned} ans_2=\sum_{i=1}^n \mu(i) \end{aligned}\) \(\color{#0066ff}{输 入 格 式}\) 一共T+1行 第1行为数据组数T(T<=10) 第2~T+1行每行一个非负整数N

【模板】杜教筛(Sum)

传送门 Description 给定一个正整数\(N(N\le2^{31}-1)\) 求 \[ans1=\sum_{i=1}^n \varphi(i)\] \[ans_2=\sum_{i=1}^n \mu(i)\] Solution 总算是写了一个不会\(TLE\)的杜教筛,不想用\(map\),因此上了一个很丑的\(Hash\)-- Code #include<bits/stdc++.h> #define ll long long #define max(a,b) ((a)>(b)?(