BZOJ 3944: Sum (杜教筛模板)
来源:互联网 发布:php中的魔术常量 编辑:程序博客网 时间:2024/05/17 21:55
题目传送门
题目分析
杜教筛模板题,人生中第一道杜教筛。
在这里推荐一篇非常棒的文章。【skywalkert’s space】
相信大多数人都是从这里开始了解和学习杜教筛的。
解题方法我就不一条公式一条公式的敲进去了,直接引用该文章中的片段:
其实杜教筛就分为两个主要部分,一个是在所有询问之前的线性筛,预处理出
ps:用hash一般比用map要快,我采用手写hash的做法,代码会略长(我就没写过几次hash)。
还有,一开始我RE到死,原因竟然是有几个地方爆了int(谁叫我作死开int),要注意处理强转的细节,或者多用long long。
代码
#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <cmath>#include <algorithm>#define N 1000010#define M 2333333using namespace std;typedef long long LL;int T, n, cnt;bool vis[N];int miu[N], prime[N];LL phi[N];int hash_n1[M], hash_n2[M], hash_v2[M];LL hash_v1[M];void Da(){ miu[1] = 1; vis[1] = true; phi[1] = 1ll; for(int i = 2; i < N; i++){ if(!vis[i]){ prime[++cnt] = i; miu[i] = -1; phi[i] = (LL)(i-1); } for(int j = 1; j <= cnt && i * prime[j] < N; j++){ vis[i * prime[j]] = true; if(i % prime[j] == 0){ miu[i * prime[j]] = 0; phi[i * prime[j]] = phi[i] * (LL)prime[j]; break; } else{ miu[i * prime[j]] = -miu[i]; phi[i * prime[j]] = phi[i] * (LL)(prime[j]-1); } } } for(int i = 1; i < N; i++) phi[i] += phi[i-1], miu[i] += miu[i-1];}LL Find1(int x){ int p = x % M; while(hash_n1[p] && hash_n1[p] != x) p = (p+1) % M; if(!hash_n1[p]) return -1; return hash_v1[p];}int Find2(int x){ int p = x % M; while(hash_n2[p] && hash_n2[p] != x) p = (p+1) % M; if(!hash_n2[p]) return -1; return hash_v2[p];}void Push1(LL v, int x){ int p = x % M; while(hash_n1[p]) p = (p+1) % M; hash_v1[p] = v; hash_n1[p] = x;}void Push2(int v, int x){ int p = x % M; while(hash_n2[p]) p = (p+1) % M; hash_v2[p] = v; hash_n2[p] = x;}LL Sum_Phi(int x){ if(x < N) return phi[x]; LL res = Find1(x); if(~ res) return res; else res = (LL)x * ((LL)x+1) >> 1; int last; for(int i = 2;; i = last+1){ last = x/(x/i); res -= (LL)(last-i+1) * Sum_Phi(x/i); if(last >= x) break; } Push1(res, x); return res;}int Sum_Miu(int x){ if(x < N) return miu[x]; int res = Find2(x); if(~ res) return res; else res = 1; int last; for(int i = 2;; i = last+1){ last = x/(x/i); res -= (last-i+1) * Sum_Miu(x/i); if(last >= x) break; } Push2(res, x); return res;}int main(){ freopen("bzoj3944.in", "r", stdin); freopen("bzoj3944.out", "w", stdout); Da(); scanf("%d", &T); while(T --){ scanf("%d", &n); printf("%lld %d\n", Sum_Phi(n), Sum_Miu(n)); } return 0;}
阅读全文
0 0
- [杜教筛模板] BZOJ 3944 Sum
- BZOJ 3944: Sum (杜教筛模板)
- bzoj 3944: Sum 杜教筛
- bzoj 3944: Sum 杜教筛
- 【BZOJ 3944】sum 杜教筛
- bzoj 3944 sum 杜教筛
- bzoj 3944 Sum 杜教筛
- [BZOJ 3944]Sum:杜教筛
- BZOJ 3944: Sum 杜教筛
- bzoj 3944 Sum 杜教筛
- [BZOJ]3944 Sum 杜教筛
- bzoj 3944: Sum (杜教筛)
- BZOJ 3944 Sum 数论
- BZOJ 3944: Sum
- BZOJ 3944 Sum
- bzoj 3944 Sum
- [BZOJ]3944: Sum
- bzoj 3944: Sum
- BZOJ 2440 [中山市选2011]完全平方数 (容斥)
- Java逻辑运算符和位运算符详解
- Python中的生成器——yield
- 杭电acm1335 n进制转化m进制
- Git 查找提交
- BZOJ 3944: Sum (杜教筛模板)
- X1000 SPI 时钟获取失败
- ITOO---选课里的“秒杀”业务实现(一)
- 信息系统开发与管理
- 【ulua入门】ulua中的update函数Timer.New()
- uva 272 TEX Quotes
- 如何在matplotlib里显示中文
- 编程笔试——推箱子
- rabbitmq 交换模式-Topic