Sum HDU

来源:互联网 发布:战舰世界淘宝商城 编辑:程序博客网 时间:2024/05/22 12:56

Sum(HDU 4407)

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.

Sample Input
13 32 2 31 1 3 41 2 3 6
Sample Output
70

题意:

一个长度为n的序列,开始的序列为1,2,3....n;

然后又两种操作。

operation1: 询问区间[a,b]中与p互质的数的和。

operation2:将序号为i的数修改为x;

如果没有修改操作,那么狠明显就是一个容斥原理

计数的问题。

分析:刚开始看题的时候,理解错了题意,耽误了很多时间,对于操作一,要求的是区间中与p互质数的和,就是区间中与p互质的数加起来。因为在进行操作二之前,这样的区间是等差数列,所以可先出这个区间所有数的和,然后减去与p不互质的数的和,就是所求的结果(这里用到了容斥原理的变形),对p进行素因子分解,不符合条件的数就是这些素因子的倍数的和,对于每一次操作,
sum=k*1+k*2+k*3+。。。。+k*m(其中k*m<=b&&k(m+1)>=b).

  这里用到了map,map既保存了未修改前的数,又保存了修改之后的数,具有对应关系。。至于修改,由于修改次数比较小,把修改存起来,对于每个查询,一个个改过去。



#include<cstdio>#include<vector>#include<iostream>#include<map>using namespace std;vector<int>x;map<int,int>Map;void getPrimeFactor(int n)///对n进行素因子的分解{                         ///容斥原理的必须步骤    x.clear();    for(int i=2;i*i<=n;i++)        if(n%i==0)    {        x.push_back(i);        while(n%i==0)            n/=i;    }    if(n!=1)        x.push_back(n);}bool gcd(int a,int b)///判断两个数是否互质{                    ///互质返回true;否则返回false;    while(b)    {        int t=a;        a=b;        b=t%b;    }    if(a==1)        return true;    else        return false;}long long solve(int b,int p)///容斥原理的简单变形,要求的不是互质的个数{                           ///而是互质数的和    long long ans=(long long)b*(1+b)/2;    long long sum=0;    for(int i=1;i<(1<<x.size());i++)    {        int cnt=0;        long long k=1;        for(int j=0;j<x.size();j++)            if(i&(1<<j))        {            cnt++;            k*=x[j];        }        k=(b/k)*(k+(b/k)*k)/2;        if(cnt&1)            sum+=k;        else            sum-=k;    }    return ans-sum;}long long sub(long long ans,int a,int b,int p)///修改{    map<int,int>::iterator it;    for(it=Map.begin();it!=Map.end();it++)    {        int f1=gcd(p,it->second);        int f2=gcd(p,it->first);        if(it->first<=b&&it->first>=a)        {            if(f1) ans+=it->second;            if(f2) ans-=it->first;        }    }    return ans;}int main(){    int t;    cin>>t;    int n,m;    while(t--)    {        Map.clear();        scanf("%d%d",&n,&m);        int x,y,p;        while(m--)        {            scanf("%d",&x);            if(x==1)            {                scanf("%d%d%d",&x,&y,&p);                getPrimeFactor(p);                cout<<sub(solve(y,p)-solve(x-1,p),x,y,p)<<endl;            }            else            {                scanf("%d%d",&x,&p);                Map[x]=p;            }        }    }    return 0;}