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了无数次,改了好久,是因为我忽略的一点,对x位置的数有可能进行多次修改,我们只需考虑最后一次修改即可。所以可用用map保存一下操作2。

#include <stdio.h>
#include <iostream>
#include <map>
#include <set>
#include <bitset>
#include <list>
#include <stack>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
#include <algorithm>
#define LL __int64
//#define LL long long
#define eps 1e-9
#define PI acos(-1.0)
using namespace std;

const int maxn = 400010;

int n,m;
bool flag[maxn];
int prime[maxn];
int fac[100];
int facCnt;
LL ans;
map<int,int>M;

int gcd(int a, int b)
{
    if(b == 0)
        return a;
    return gcd(b,a%b);
}

void getPrime()
{
    memset(flag,false,sizeof(flag));
    prime[0] = 0;
    for(int i = 2; i < maxn; i++)
    {
        if(flag[i] == false)
            prime[++prime[0]] = i;
        for(int j = 1; j <= prime[0]&&prime[j]*i < maxn; j++)
        {
            flag[prime[j]*i] = true;
            if(i % prime[j] == 0)
                break;
        }
    }
}

void getFac(int num)
{
    int tmp = num;
    facCnt = 0;
    for(int i = 1; i <= prime[0]&&prime[i]*prime[i] <= tmp; i++)
    {
        if(tmp % prime[i] == 0)
        {
            fac[facCnt++] = prime[i];
            while(tmp % prime[i] == 0)
                tmp /= prime[i];
        }
        if(tmp == 1)
            break;
    }
    if(tmp > 1)
        fac[facCnt++] = tmp;
}

LL getSum(int t)
{
    return ((1 + 1LL * t) * 1LL * t) >> 1;
}

//求【1,r】内与该数互质的数之和。
LL cal(int r)
{
    LL anw = getSum(r);
    LL tmp = 0;

    for(int i = 1; i < (1<<facCnt); i++)
    {
        LL mul = 1;
        int cnt = 0;
        for(int j = 0; j < facCnt; j++)
        {
            if(i&(1<<j))
            {
                mul *= fac[j];
                cnt++;
            }
        }
        if(cnt&1)
            tmp += mul * getSum((LL)r/mul);
        else tmp -= mul * getSum((LL)r/mul);
    }
    return anw - tmp;
}

int main()
{
    getPrime();
    int test;
    scanf("%d",&test);
    while(test--)
    {
        M.clear();
        int op,x,y,z;

        scanf("%d %d",&n,&m);
        for(int i = 1; i <= m; i++)
        {
            scanf("%d",&op);
            if(op == 1)
            {
                scanf("%d %d %d",&x,&y,&z);
                getFac(z);
                ans = cal(y) - cal(x-1);

                //printf("ans : %I64d\n",ans);

                map<int,int>::iterator it;
                for(it = M.begin(); it != M.end(); it++)
                {
                   if(it->first >= x && it->first <= y)
                   {
                        if(gcd(z,it->first) == 1)
                            ans -= it->first;
                        if(gcd(z,it->second) == 1)
                            ans += it->second;
                   }
                }
                printf("%I64d\n",ans);
            }
            else
            {
                scanf("%d %d",&x,&y);
                M[x] = y;
            }
        }
    }
    return 0;
}
时间: 2024-10-24 01:48:17

hdu 4407 Sum(容斥)的相关文章

hdu 4407 Sum 容斥+离线

求X-Y之间和p互质的数的和,典型的容斥问题,求和用等差数列求和,注意首项末项是多少. 首先记录下不修改的答案,离线处理,存下询问,输出的时候,遇到一个操作1,就遍历前面的操作,把修改加上去,注意要判重,只保留最后一次修改. #include <stdio.h> #include <vector> #include <algorithm> #include <cmath> #include <iostream> #include<cstri

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不互质的数),再用