• 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
    ", ori[n].phi, ori[n].miu);
    92         else
    93         {
    94             couple answer = Solve(n);
    95             printf("%lld %lld
    ", answer.phi, answer.miu);
    96         }
    97     }
    98
  • 相关阅读:
    如何在软件频繁改变时测试?归纳总结
    PE文件格式资源
    PE文件格式重定位
    PEB模块链表Ldr
    PE文件格式导入表和IAT
    PE文件格式导出表
    win32汇编问题指令
    win32汇编问题堆栈
    硬盘基本知识
    SEH异常处理
  • 原文地址:https://www.cnblogs.com/lytccc/p/6661487.html
Copyright © 2020-2023  润新知