【BZOJ3944】 Sum

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
2 0
22 -2
58 -3
278 -3
1655470 2

Solution

裸的杜教筛。具体的内容详见洲阁2015年的集训队论文。这里我就大致口胡一下,求一个积性函数的前缀和可以把它狄利克雷卷积上另一个函数,同时卷上的这个函数和卷完得到的这个函数如果都很好求前缀和的话,那么就可以用杜教筛来求。phi函数大致的推导如下:

 

 Code

 1 #include <cstdio>
 2 #include <map>
 3 
 4 #define R register
 5 #define maxn 2000010
 6 typedef long long ll;
 7 int phi[maxn], miu[maxn], pr[maxn / 10], prcnt;
 8 ll sph[maxn], smi[maxn];
 9 bool vis[maxn];
10 const int moha = 3333331;
11 struct Hash {
12     Hash *next;
13     int ps; ll ans;
14 } *last1[moha], *last2[moha], mem[moha], *tot = mem;
15 inline ll S1(R int n)
16 {
17     if (n < maxn) return sph[n];
18     for (R Hash *iter = last1[n % moha]; iter; iter = iter -> next)
19         if (iter -> ps == n) return iter -> ans;
20 
21     R ll ret = 1ll * n * (n + 1ll) / 2;
22     for (R ll i = 2, j; i <= n; i = j + 1)
23     {
24         j = n / (n / i);
25         ret -= S1(n / i) * (j - i + 1);
26     }
27     *++tot = (Hash) {last1[n % moha], n, ret}; last1[n % moha] = tot;
28     return ret;
29 }
30 inline ll S2(R int n)
31 {
32     if (n < maxn) return smi[n];
33     for (R Hash *iter = last2[n % moha]; iter; iter = iter -> next)
34         if (iter -> ps == n) return iter -> ans;
35 
36     R ll ret = 1;
37     for (R ll i = 2, j; i <= n; i = j + 1)
38     {
39         j = n / (n / i);
40         ret -= (j - i + 1) * S2(n / i);
41     }
42     *++tot = (Hash) {last2[n % moha], n, ret}; last2[n % moha] = tot;
43     return ret;
44 }
45 int main()
46 {
47     R int T; scanf("%d", &T);
48     phi[1] = sph[1] = 1;
49     miu[1] = smi[1] = 1;
50     for (R int i = 2; i < maxn; ++i)
51     {
52         if (!vis[i]) pr[++prcnt] = i, phi[i] = i - 1, miu[i] = -1;
53         sph[i] = sph[i - 1] + phi[i];
54         smi[i] = smi[i - 1] + miu[i];
55         for (R int j = 1; j <= prcnt && 1ll * i * pr[j] < maxn; ++j)
56         {
57             vis[i * pr[j]] = 1;
58             if (i % pr[j])
59             {
60                 phi[i * pr[j]] = phi[i] * (pr[j] - 1);
61                 miu[i * pr[j]] = -miu[i];
62             }
63             else
64             {
65                 phi[i * pr[j]] = phi[i] * pr[j];
66                 miu[i * pr[j]] = 0;
67                 break;
68             }
69         }
70     }
71     for (; T; --T)
72     {
73         R int N; scanf("%d", &N);
74 //        printf("%d\n", N);
75         printf("%lld %lld\n", S1(N), S2(N));
76     }
77     return 0;
78 }
79 /*
80 6
81 1
82 2
83 8
84 13
85 30
86 2333
87 */

 

posted @ 2017-07-01 10:49  cot  阅读(191)  评论(0编辑  收藏  举报