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
*/
时间: 2024-10-17 01:03:41

hdu 4407 Sum 容斥+离线的相关文章

hdu 4407 Sum(容斥)

http://acm.hdu.edu.cn/showproblem.php?pid=4407 起初有n个数1~n,这里有m个操作,两种类型.操作1:求出[x,y]区间内与p互质的数的和.操作2:将第x位置的数变成y.对于每一个询问,输出结果. 因为只有1000次操作,而且起初是有序的.那么对于第i个询问,我们先忽略i之前的所有的第2种操作,即认为n个数为1~n,根据容斥原理求出[x,y]区间内与p互质的数之和,然后遍历i之前的操作2,对所求的答案进行调整即可.wa了无数次,改了好久,是因为我忽略

hdu 5514 Frogs(容斥)

Frogs Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1315    Accepted Submission(s): 443 Problem Description There are m stones lying on a circle, and n frogs are jumping over them.The stones a

HDU 5213 分块 容斥

给出n个数,给出m个询问,询问 区间[l,r] [u,v],在两个区间内分别取一个数,两个的和为k的对数数量. $k<=2*N$,$n <= 30000$ 发现可以容斥简化一个询问.一个询问的答案为 $[l,v]+(r,u)-[l,u)-(r,v]$,那么我们离线询问,将一个询问分成四个,分块暴力就行了. 然后就是注意细节,不要发生越界,访问错位置之类比较蠢的问题了. /** @Date : 2017-09-24 19:54:55 * @FileName: HDU 5213 分块 容斥.cpp

hdu4407 Sum 容斥+暴力

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): 1990    Accepted Submission(s): 564 Problem Description XXX is puzzled with the question below

hdu 5212 反向容斥或者莫比

http://acm.hdu.edu.cn/showproblem.php?pid=5212 题意:忽略.. 题解:把题目转化为求每个gcd的贡献.(http://www.cnblogs.com/z1141000271/p/7419717.html 和这题类似 反向容斥)这里先用容斥写了,mobious的之后再说吧23333. 然后比较想说的是这个调和级数的复杂度 nlog(n) ac代码: #include <iostream> #include <cstdio> #includ

hdu 5514 Frogs 容斥思想+gcd 银牌题

Frogs Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1509    Accepted Submission(s): 498 Problem Description There are m stones lying on a circle, and n frogs are jumping over them.The stones a

HDU 6053 TrickGCD 容斥

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=6053 题意: 给你序列a,让你构造序列b,要求 1<=b[i]<=a[i],且b序列的gcd>=2.问你方案数. 思路: 容易想到的就是我们枚举整个序列的gcd,然后a[i]/gcd就是i位置能够填的数的个数,然后每个位置累积就能得到数列为gcd时的方案数. 最后容斥一下累加就是答案.但是最大gcd可以是100000和明显这样做n^2,会超时. 那么我们把a[i]/gcd的放在一起,然后用

HDU 1695 GCD(容斥 or 莫比乌斯反演)

这题可以用容斥做,然而效率并不高.. 于是学了下莫比乌斯反演(资料百度找) 求出mo数组后 设f(x)为gcd为x的种数 F(x)为gcd为x倍数的种数 那么显然F(x) = (b / x) * (d / x) 莫比乌斯反演之后,得到f(x) = sum(mo[i] * F(i)). 然后还要容斥减去对称重复的.对称重复的情况为min(b, d)小的中,求一遍除2,(因为存在x = y的情况只有(1,1)一种) 最后还要注意特判下k == 0的情况 代码: #include <cstdio>

HDU 4135 Co-prime (容斥+分解质因子)

<题目链接> 题目大意: 给定区间[A,B](1 <= A <= B <= 10 15)和N(1 <=N <= 10 9),求出该区间中与N互质的数的个数. 解题分析: 将求区间[A,B]与N互质的数转化成求[1,B] 区间与N互质的个数  -  [1,A-1]中与N互质的个数.同时,因为直接求区间内与N互质的数不好求,我们从反面入手,求出与N不互质的数,借鉴埃筛的思想,我们先求出N的所有质因子,然后将这些质因子在区间内倍数的个数全部求出(即与N不互质的数),再用