Sum BZOJ 3944

Sum

【问题描述】

给定一个正整数 N ( N <= 231 - 1 )

求:

【输入格式】

一共T+1行
第1行为数据组数T(T<=10)
第2~T+1行每行一个非负整数N,代表一组询问

【输出格式】

一共T行,每行两个用空格分隔的数ans1,ans2
【样例输入】

6
1
2
8
13
30
2333

【样例输出】

1 1
2 0
22 -2
58 -3
278 -3
1655470 2


题解

首先推一波式子

上式就是杜教筛的原理

 

 

:

 

 

 :

 

 

 

对于的求解方式在上面已经给出了

那么求出前项答案并记忆化状态,就能达到的时间复杂度

由于  ,那么我们求的每一项的参数都是  形式的

对于  小于等于的答案我们已经预处理出了

所以我们只需要记忆大于的答案

首先提出一个命题:对于  都不相同

证明:

假设 ,且

那么

mi , m表示两者的余数,它们的差为

因为,所以

那么,而,假设不成立

所以不存在,使得

证毕

所以在 时,成立

那么,我们就能直接使用数组存,对于每一个参数,我们将其除k的结果作为下标储存答案

 1 #include<cmath>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<iostream>
 6 #include<algorithm>
 7 using namespace std;
 8 const int maxm = 2e6 + 1;
 9 const int maxn = 1e4 + 1;
10 int n;
11 int pri[maxm];
12 bool vis[maxm];
13 struct couple
14 {
15     long long miu, phi;
16 };
17 couple ans[maxn], ori[maxm];
18 inline void Scan(int &x)
19 {
20     char c;
21     bool o = false;
22     while(!isdigit(c = getchar())) o = (c != '-') ? o : true;
23     x = c - '0';
24     while(isdigit(c = getchar())) x = x * 10 + c - '0';
25     if(o) x = -x;
26 }
27 int m;
28 inline void Sieve()
29 {
30     int tot = 0;
31     m = maxm - 1;
32     ori[1] = (couple) {1, 1};
33     for(int i = 2; i <= m; ++i)
34     {
35         if(!vis[i])
36         {
37             pri[++tot] = i;
38             ori[i] = (couple) {-1, i - 1};
39         }
40         for(int j = 1; j <= tot; ++j)
41         {
42             int k = pri[j];
43             long long s = (long long) i * k;
44             if(s > m) break;
45             vis[s] = true;
46             if(!(i % k))
47             {
48                 ori[s].miu = 0;
49                 ori[s].phi = ori[i].phi * k;
50                 break;
51             }
52             else
53             {
54                 ori[s].miu = -ori[i].miu;
55                 ori[s].phi = ori[i].phi * ori[k].phi;
56             }
57         }
58     }
59     for(int i = 1; i <= m; ++i)
60     {
61         ori[i].miu += ori[i - 1].miu;
62         ori[i].phi += ori[i - 1].phi;
63     }
64 }
65 couple Solve(int x)
66 {
67     if(x <= m) return ori[x];
68     int e = n / x;
69     if(vis[e]) return ans[e];
70     int last;
71     couple c, s;
72     s.miu = 1, s.phi = x * ((long long) x + 1) >> 1;
73     for(long long i = 2; i <= x; i = (long long) last + 1)
74     {
75         last = x / (x / i);
76         c = Solve(x / i);
77         s.miu -= c.miu * (long long) (last - i + 1), s.phi -= c.phi * (long long) (last - i + 1);
78     }
79     vis[e] = true, ans[e] = s;
80     return s;
81 }
82 int main()
83 {
84     int T;
85     Scan(T);
86     Sieve();
87     while(T--)
88     {
89         Scan(n);
90         memset(vis, false, sizeof(vis));
91         if(n <= m) printf("%lld %lld\n", ori[n].phi, ori[n].miu);
92         else
93         {
94             couple answer = Solve(n);
95             printf("%lld %lld\n", answer.phi, answer.miu);
96         }
97     }
98
posted @ 2017-04-03 11:02  草根柴鸡  阅读(155)  评论(0编辑  收藏  举报