zoukankan      html  css  js  c++  java
  • hdu4407Sum(容斥原理)

    http://acm.hdu.edu.cn/showproblem.php?pid=4407

    Sum

    Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 1551    Accepted Submission(s): 232
    Problem Description
    XXX is puzzled with the question below:

    1, 2, 3, ..., n (1<=n<=400000) are placed in a line. There are m (1<=m<=1000) operations of two kinds.

    Operation 1: among the x-th number to the y-th number (inclusive), get the sum of the numbers which are co-prime with p( 1 <=p <= 400000).
    Operation 2: change the x-th number to c( 1 <=c <= 400000).

    For each operation, XXX will spend a lot of time to treat it. So he wants to ask you to help him.
     
    Input
    There are several test cases.
    The first line in the input is an integer indicating the number of test cases.
    For each case, the first line begins with two integers --- the above mentioned n and m.
    Each the following m lines contains an operation.
    Operation 1 is in this format: "1 x y p".
    Operation 2 is in this format: "2 x c".
     
    Output
    For each operation 1, output a single integer in one line representing the result.
     
    SampleInput
    1
    3 3
    2 2 3
    1 1 3 4
    1 2 3 6
     
    SampleOutput
    7
    0

    给定一个数x可以表示成p = p1i1p2i2...pnin;要求x,x+1,x+2,...y与x互质的数的和,等价于求x,x+1,x+2,...y与p=p1p2...pn互质。(p1,p2,...,pn为素数)

    x,x+1,x+2,...y与p互质直接求不好求,所以可以反过来求,先求出与x不互质的数的和sum,然后ans=总的和-sum。

    sum[[x,x+1,x+2,...y]与p不互质]=sum[[1,2,...y]与p不互质] - sum[[1,2,x-1]与p不互质],

    考虑p的素因子pi,则[1..y]中与pi不互质的数的个数是[y/pi].

    然而,如果我们单纯将所有结果相加,有些数就会被统计多次(被好几个素因子整除)。所以,我们要运用容斥原理来解决。

    http://zh.wikipedia.org/wiki/容斥原理

    比如要求[1,2,...,10]和10不互质的和,10=2*5,与2不互质的有2,4,6,8,10,与5不互质的有5,10;但还要减去与2*5不互质10;每个与pi不互质的是一个等差数列,

    所以等差数列求和即可。

    (因为m最多1000,所以修改的数不多,所以后面对修改的数单独处理就ok了。)

    第一步要求x的所有因子。

    第二步运用容斥原理,奇数项加,偶数项减。

    再枚举修改的值就差不多了。

    n<=400000,所以ans可能会超int

     1 int size;//因子个数
     2 int yinzi[100];
     3 void get_yinzi(int n)
     4 {
     5     size = 0;
     6     if (!(n & 1))//为偶数
     7     {
     8         yinzi[size++] = 2;
     9         while (n /= 2, !(n & 1));
    10     }
    11     int i, sqrtn = (sqrt(1.0 * n) + 0.5);
    12     for (i = 3; i <= sqrtn; i += 2)
    13     {
    14         if (n % i == 0)
    15         {
    16             yinzi[size++] = i;
    17             while (n /= i, n % i == 0);
    18         }
    19         if (n == 1)
    20             return;
    21     }
    22     if (n > 1)
    23         yinzi[size++] = n;
    24 }
    //详见大牛博客http://www.cnblogs.com/xin-hua/p/3213050.html
    1
    #define llt long long int 2 llt solve(int r)//容斥原理,二进制法,总共有2size-1项 3 { 4 llt sum = 0; 5 int bits;//1的个数,奇数加,偶数减 6 int pi;// 7 int i, j = 1 << size, t; 8 int k;//选中的第几个因子 9 for (i = 1; i < j; i++)//看i的二进制表示,假设size=4,i=1011,表示yinzi[3]∩yinzi[1]∩yinzi[0]即pi = yinzi[3]*yinzi[1]*yinzi[0] 10 { 11 pi = 1; 12 t = i; 13 k = bits = 0; 14 while (t) 15 { 16 if (t & 1) 17 { 18 pi *= yinzi[k]; 19 bits++; 20 } 21 k++; 22 t >>= 1; 23 } 24 t = r / pi; 25 if (bits & 1)//等差数列求和 26 sum += 1ll * (pi + pi * t) * t / 2; 27 else 28 sum -= 1ll * (pi + pi * t) * t / 2; 29 } 30 return sum; 31 }
     1 int gcd(int a, int b)
     2 {
     3     return b ? gcd (b, a % b) : a; 
     4 }
     5 
     6 llt sum(int n)
     7 {
     8     return 1ll * (1 + n) * n / 2;
     9 }
    10 map<int, int> mp;//使用map对修改的数进行操作
    11 map<int,int>::iterator it;
    12 int main()
    13 {
    14     int tests, n, m, i, op, x, y, p, c;
    15     llt ans;
    16     scanf("%d", &tests);
    17     while (tests--)
    18     {
    19         mp.clear();
    20         scanf("%d%d", &n, &m);
    21         while (m--)
    22         {
    23             scanf("%d", &op);
    24             if (op == 1)
    25             {
    26                 ans = 0;
    27                 scanf("%d%d%d", &x, &y, &p);
    28                 if (x > y)
    29                     swap(x, y);
    30                 get_yinzi(p);
    31                 for (it = mp.begin(); it != mp.end(); it++)
    32                 {
    33                     if (it->first != it->second && it->first >= x && it->first <= y)
    34                     {
    35                         ans -= gcd(it->first, p) == 1 ? it->first : 0;
    36                         ans += gcd(it->second, p) == 1 ? it->second : 0;
    37                     }
    38                 }
    39                 printf("%I64d
    ", ans + sum(y) - sum(x - 1) - solve(y) + solve(x - 1));
    40             }
    41             else
    42             {
    43                 scanf("%d%d", &x, &c);
    44                 mp[x] = c;
    45             }
    46         }
    47     }
    48     return 0;
    49 }    
  • 相关阅读:
    Nexus3.0私服搭建
    JavaScript
    Spring基础
    Hibernate注解
    HTML5
    Apache Tomcat
    Java安装(Ubuntu)
    C++ 日期 & 时间
    C++ 引用
    C++ 指针
  • 原文地址:https://www.cnblogs.com/jecyhw/p/hdu4407Sum.html
Copyright © 2011-2022 走看看