HDU5608 function

解:显然f那个式子可以反演一波,然后再推一波,最后出来了这个......

其中M是莫比乌斯函数的前缀和。虽然看起来能算...感觉很毒瘤,复杂度也不会。

正解:杜教筛的套路是对一个卷函数求前缀和,然后拆开。

于是我们直接对(i2 - 3i + 2)求前缀和,之后就是一个很普通的杜教筛式子了......

如何预处理f?利用反演式子,考虑每个(i2 - 3i + 2)会对哪些f有所贡献即可。复杂度调和级数。

注意long long和取模...我全程爆炸调了一晚上。

 1 #include <cstdio>
 2 #include <cmath>
 3 #include <cstring>
 4 #include <map>
 5 
 6 typedef long long LL;
 7 const int N = 1000010, T = 1000008;
 8 const LL MO = 1e9 + 7, inv6 = 166666668, inv2 = 500000004, INF = 0x7f7f7f7f7f7f7f7fll;
 9 
10 int miu[N], p[N], top;
11 LL F[N], n;
12 std::map<LL, LL> F2;
13 bool vis[N];
14 
15 inline LL qpow(LL a, LL b) {
16     LL ans = 1;
17     while(b) {
18         if(b & 1) ans = ans * a % MO;
19         a = a * a % MO;
20         b = b >> 1;
21     }
22     return ans;
23 }
24 
25 inline LL G(LL x) {
26     x %= MO;
27     return (((x * 2 + 1) % MO) * inv6 % MO * x % MO * ((x + 1) % MO) % MO -
28     ((x + 1) % MO) * inv2 % MO * x % MO * 3 % MO + x * 2 % MO) % MO;
29 }
30 
31 inline LL g(LL x) {
32     x %= MO;
33     return (x * x % MO - 3 * x % MO + 2 + MO) % MO;
34 }
35 
36 inline void prework() {
37     /// get miu
38     miu[1] = 1;
39     for(int i = 2; i <= T; i++) {
40         if(!vis[i]) {
41             p[++top] = i;
42             miu[i] = -1;
43         }
44         for(int j = 1; j <= top && i * p[j] <= T; j++) {
45             vis[i * p[j]] = 1;
46             if(i % p[j] == 0) break;
47             miu[i * p[j]] = -miu[i];
48         }
49     }
50     /// getF
51     for(int i = 1; i <= T; i++) {
52         LL t = g(i);
53         for(int j = 1; i * j <= T; j++) {
54             F[i * j] += t * miu[j] % MO;
55             F[i * j] = (F[i * j] % MO + MO) % MO;
56         }
57     }
58     for(int i = 1; i <= T; i++) {
59         F[i] = (F[i] + F[i - 1]) % MO;
60     }
61     return;
62 }
63 
64 LL solve(LL x) {
65     if(x <= 0) return 0;
66     if(x <= T) return F[x];
67     if(F2.count(x)) return F2[x];
68     LL ans = G(x);
69     for(LL i = 2, j; i <= x; i = j + 1) {
70         j = x / (x / i);
71         ans -= solve(x / i) * (j - i + 1) % MO;
72         ans = (ans % MO + MO) % MO;
73     }
74     return F2[x] = ans;
75 }
76 
77 int main() {
78     int q;
79     scanf("%d", &q);
80     prework();
81     //printf("q = %d \n", q);
82     for(int i = 1; i <= q; i++) {
83         //printf("i = %d q = %d \n", i, q);
84         scanf("%lld", &n);
85         printf("%lld\n", solve(n));
86     }
87     return 0;
88 }
AC代码

 

转载于:https://www.cnblogs.com/huyufeifei/p/10440616.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值