hdu 4407 Sum 容斥+离线

来源:互联网 发布:linux vnc 安装 编辑:程序博客网 时间:2024/05/18 02:01

求X-Y之间和p互质的数的和,典型的容斥问题,求和用等差数列求和,注意首项末项是多少。

首先记录下不修改的答案,离线处理,存下询问,输出的时候,遇到一个操作1,就遍历前面的操作,把修改加上去,注意要判重,只保留最后一次修改。

#include <stdio.h>#include <vector>#include <algorithm>#include <cmath>#include <iostream>#include<cstring>using namespace std;typedef long long ll;ll ans;int pri[1234];int top;int n,m,a,b,c;ll gcd(ll a,ll b){    return a%b==0?b:gcd(b,a%b);}ll cal(ll num){    int x=a;    int y=b;    int fir;    int tmp=y/num-x/num;    if(x%num==0) fir=x,tmp++;    else fir=num*(x/num+1);    if(fir>y) return 0;    int en=fir+(tmp-1)*num;    return (fir+en)*1ll*tmp/2;}void dfs(int p,ll num,int flag){    if(num>b) return;    if(p) {ans+=flag*cal(num);}    for(int i=p+1;i<top;i++)    {        dfs(i,pri[i]*num,-flag);    }}ll out[1234];int d[1234][4];int rec[1234][2];bool vis[400005];bool V[400005];int prime[400005];int topp=0;void sieve(int n){    int m= (int)sqrt(n+0.5);    for(int i=2;i<=m;i++)    {        if(!V[i])        {            for(int j=i*i;j<=n;j+=i)                V[j]=1;        }    }    V[1]=1;    for(int i=2;i<=400000;i++)    {        if(V[i]==0) prime[topp++]=i;    }}int main(){    sieve(400005);    int cas;    scanf("%d",&cas);    while(cas--)    {        scanf("%d%d",&n,&m);        int op;        for(int i=1;i<=m;i++)        {            scanf("%d",&op);            d[i][0]=op;            if(op==1)            {                ans=0;                top=1;                scanf("%d%d%d",&a,&b,&c);                d[i][1]=a;                d[i][2]=b;                d[i][3]=c;                if(c==1)                {                    out[i]=(a+b)*1ll*(b-a+1)/2;                    continue;                }                for(int j=0;prime[j]*prime[j]<=c;j++)                {                    if(V[c]==0) break;                    if(c%prime[j]==0)                    {                        pri[top++]=prime[j];                        while(c%prime[j]==0) c/=prime[j];                    }                }                if(c>1) pri[top++]=c;                dfs(0,1,-1);                out[i]=(a+b)*1ll*(b-a+1)/2-ans;            }            else            {                scanf("%d%d",&b,&c);                d[i][1]=b;                d[i][2]=c;            }        }        for(int i=1;i<=m;i++)        {            if(d[i][0]==1)            {                ll ans=out[i];                int cnt=0;                for(int j=i-1;j>=1;j--)                {                    if(d[j][0]==2&&!vis[d[j][1]])                    {                        vis[d[j][1]]=true;                        rec[cnt][0]=d[j][1];                        rec[cnt][1]=d[j][2];                        cnt++;                    }                }                for(int j=0;j<cnt;j++)                {                    vis[rec[j][0]]=false;                    if(rec[j][0]>=d[i][1]&&rec[j][0]<=d[i][2])                    {                        ans-=( gcd(rec[j][0],d[i][3])==1?rec[j][0]:0 );                        ans+=( gcd(rec[j][1],d[i][3])==1?rec[j][1]:0 );                    }                }                printf("%I64d\n",ans);            }        }    }    return 0;}/*123100 11 1 10 112 2 32 2 51 1 10 2*/


0 0
原创粉丝点击