(hdu4407)Sum(容斥原理)

来源:互联网 发布:数据共享的方式 编辑:程序博客网 时间:2024/05/17 22:50

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3639 Accepted Submission(s): 1047

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.

Sample Input
1
3 3
2 2 3
1 1 3 4
1 2 3 6

Sample Output
7
0

Source
2012 ACM/ICPC Asia Regional Jinhua Online

题意:给定n和m,m个操作,操作有以下两种类型:
1. 1 x y p 计算[x,y]内与p互质的数的总和
2. 2 x c 将第x个数改为c(最多1000次)
输出操作1所求的和

分析:求[x,y]内与p互质的数,这里和 hdu4315(http://blog.csdn.net/feng_zhiyu/article/details/76176070) 类似 对p分解,求出其素因子并储存
设 p 的素因子是{P1,P2,…,Pk},于是与 p 不互质的数的素因子集合可以表示成 {P1} U {P2} U … U {Pk}。
那么与 p 不互质的数的集合可以表示成 W = { P1的倍数 } U { P2的倍数 } U … U { Pk的倍数 }。
其中,{ Pk的倍数 } = { Pk*1 } + { Pk*2 } + … + { Pk*Mk } ( Pk*Mk<=n && Pk*(Mk+1)>n )。
从而,ans = sum{ W }。
于是可以通过容斥原理,求得问题的解。
举个简单的例子,假如 k=2,则 ans = 【sum{ P1的倍数 } + sum{ P2的倍数 } - sum{ P1*P2的倍数 }】。其中,某个sum{ }可以通过等差公式求得。
第二种操作 直接一一判断

打算把容斥原理的三种方法都用一遍,但开始我用队列的时候TLE了,发现有一个地方写错了,改了过来变成了WA。。 感觉没问题。。 dfs也有点问题。。 先放上来。。。

#include<cstdio>#include<map>#include<cstring>#include<algorithm>using namespace std;typedef long long LL;const LL N=1e6+5;LL vec[N];map<LL,LL>mp;LL n,m,cnt;void is_sfactor(LL n)///求n的素因子{    cnt=0;    for(LL i=2; i*i<=n; i++)    {        if(n%i==0)        {            n/=i;            vec[cnt++]=i;            while(n%i==0)                n/=i;        }    }    if(n>1) vec[cnt++]=n;}LL gcd(LL a,LL b){    return b==0?a:gcd(b,a%b);}LL que[N];LL solve(LL x,LL p)///求[1,x]内与p互质的数{    LL ans=x*(1+x)/2;//先求出总和    LL len=cnt;    /*LL k,front=0,T;    que[front++]=-1;    for(LL i=0; i<len; i++)    {        k=front;        for(LL j=0; j<k; j++)            que[front++]=que[j]*vec[i]*(-1);    }    for(LL i=1; i<front; i++)    {        T=(x/que[i])*(que[i]+(x/que[i])*que[i])/2;        if(que[i]<0)            ans+=T;        else ans-=T;    }*/    for(LL i=1; i<(1<<len); i++)///二进制位实现容斥    {        LL num=0;        LL k=1;        for(LL j=0; j<len; j++)            if(i&(1<<j))            {                num++;                k*=vec[j];            }        k=(x/k)*(k+(x/k)*k)/2;        if(num&1) ans-=k;///  奇数的 是不互质的数        else ans+=k;  //加上重复减去的    }    return ans;}LL query(LL ans,LL x,LL y,LL p){    map<LL,LL>::iterator it;    for(it=mp.begin(); it!=mp.end(); it++)    {        LL g1=it->first,g2=it->second;        if(it->first>=x&&it->first<=y) ///必须满足在查询的区间内        {            if(gcd(g1,p)==1) ans-=g1; ///原来被修改的数            if(gcd(g2,p)==1) ans+=g2;  ///修改后的数        }    }    return ans;}int main(){    LL T;    scanf("%d",&T);    while(T--)    {        mp.clear();        scanf("%lld%lld",&n,&m);        while(m--)        {            LL type,x,y,p,c;            scanf("%lld",&type);            if(type==1)            {                scanf("%lld%lld%lld",&x,&y,&p);                is_sfactor(p);                LL ans=solve(y,p)-solve(x-1,p);                //         printf("%LLd\n",ans);                printf("%lld\n",query(ans,x,y,p));            }            else            {                scanf("%lld%lld",&x,&c);                mp[x]=c;            }        }    }    return 0;}