首页 > 代码库 > hdu 4407 Sum 容斥+离线

hdu 4407 Sum 容斥+离线

求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;
}
/*
123
100 1
1 1 10 11
2 2 3
2 2 5
1 1 10 2
*/


hdu 4407 Sum 容斥+离线