HDU4407 Sum【容斥原理】

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4407

题目大意:

刚开始有一个长度为N的序列,排列为{1、2、3、…、N}。下边是M个操作指令。

有两种操作:

操作1:给你三个整数 Left Right d  求出区间[Left,Right]上与整数d互素的数的和

操作2:给你两个整数 pos d  将第pos个位置上的数改为d。

解题思路:

求出区间[Left,Right]上与整数d互素的数的和可以用容斥定理求出,类似于HDU4135

下边考虑更改操作。看了题意,1 <= M <= 1000。最多只有1000个操作,那么可以把

每次的更改操作都保存起来,在求[Left,Right]上与整数d互素的数的和时,可以先求出

原先未改变时的结果,再加上改变操作中改变的结果,即为最终结果。具体参考代码。

参考博文:http://blog.csdn.net/ok_again/article/details/11167313

AC代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define LL __int64
using namespace std;

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

int Factor[22],ct;
int A[1100],B[1100];
//A[]纪录更改位置(下标) B[]纪录更改的值
void Divide(int N)
{
    ct = 0;
    for(int i = 2; i <= sqrt(N*1.0); ++i)
    {
        if(N % i == 0)
        {
            Factor[ct++] = i;
            while(N % i == 0)
                N /= i;
        }
    }
    if(N != 1)
        Factor[ct++] = N;
}

LL Solve(int Left, int Right)
{
    LL ans = 0;
    for(int i = 1; i < (1 << ct); ++i)
    {
        int odd = 0;
        int tmp = 1;
        for(int j = 0; j < ct; ++j)
        {
            if((1 << j) & i)
            {
                odd++;
                tmp *= Factor[j];
            }
        }
        LL Num = Right / tmp - (Left-1) / tmp;  //区间[L,R]中因子tmp的倍数个数
        LL Cnt = Num * (Num+1) / 2 * tmp + ((Left-1)/tmp) * tmp * Num;  //[L,R]上因子tmp的倍数和
        if(odd & 1) //奇加偶减
            ans += Cnt;
        else
            ans -= Cnt;
    }
    return (LL)(Left+Right) * (LL)(Right-Left+1) / 2 - ans; //得到区间[L,R]与d互质的数的和
}

int main()
{
    int T,N,M,op;
    int Left,Right,d,pos;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&N,&M);
        int id = 0;
        while(M--)
        {
            scanf("%d",&op);
            if(op == 1)
            {
                scanf("%d%d%d",&Left,&Right,&d);
                Divide(d);
                LL ans = Solve(Left,Right);
                for(int i = 0; i < id; ++i)
                {
                    if(A[i] >= Left && A[i] <= Right)
                    {
                        if(GCD(d,A[i]) == 1) //因为原先第i位置上的数为i。计算[L,R]中互质数已经计算过一次,所以要减去
                            ans -= A[i];
                        if(GCD(d,B[i]) == 1) //如果更改的数与d互质,则加上该数。
                            ans += B[i];
                    }
                }
                printf("%I64d\n",ans);
            }
            else
            {
                int Flag = 0;
                scanf("%d%d",&pos,&d);
                for(int i = 0; i < id; ++ i)
                {
                    if(A[i] == pos)
                    {
                        Flag = 1;
                        B[i] = d;
                        break;
                    }
                }
                if(!Flag)
                {
                    B[id] = d;
                    A[id++] = pos;
                }
            }
        }
    }

    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-12 23:40:03

HDU4407 Sum【容斥原理】的相关文章

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

AtCoder AGC039F Min Product Sum (容斥原理、组合计数、DP)

题目链接 https://atcoder.jp/contests/agc039/tasks/agc039_f 题解 又是很简单的F题我不会... 考虑先给每行每列钦定一个最小值\(a_i,b_j\),并假设每行每列的最小值是这个数,且每行每列只需要放\(\ge\)这个数的数即可,那么这种情况的价值是\(\prod^n_{i=1}\prod^m_{j=1}\min(a_i,b_j)\), 方案数是\(\prod^n_{i=1}\prod^m_{j=1}(n+1-\max(a_i,b_j))\) 然

Sum(hdu4407)

Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2974    Accepted Submission(s): 843 Problem Description XXX is puzzled with the question below: 1, 2, 3, ..., n (1<=n<=400000) are placed in

[容斥原理] hdu 4407 Sum

题意: 有两种操作1,2 1:询问 x,y区间能与p互质的数的和 2:将x改成p 一开始给N,初始是1~N个数 思路: 我们在求不互质的数有多少个的时候 其实就可以用等差数列求和求出这些数的和 那么我们到时候直接求一下就好了 然后因为这里的操作次数很少 所以我们可以标记一下哪些位置被修改过 然后在1操作的时候 特判一下这些位置 代码: #include"cstdlib" #include"cstdio" #include"cstring" #in

BZOJ3198 SDOI2013 spring HASH+容斥原理

题意:给定6个长度为n的数列,求有多少个数对(i,j)((i,j)≡(j,i))使得i和j位置恰好有K个数相同,其中0≤K≤6 题解: 设fi=至少有K个数相同的位置对的数量,用2^6枚举每一种可能,根据容斥原理,答案就是\[\sum\limits_{i = K}^N {{f_i}C_i^K{{\left( { - 1} \right)}^{i - K}}} \] 至于多乘一个组合数,是因为当前枚举到有x个数相同,一个位置对有i个相同的数,那么累计的时候就会算成$C_x^i$,因此实际上这个位置

HDU - 4135 Co-prime(容斥原理)

Question 参考 题意找出[a,b]中与n互质的数的个数分析通常我们求1-n中与n互质的数的个数都是用欧拉函数.但如果n比较大或者是求1-m中与n互质的数的个数等等问题,要想时间效率高的话还是用容斥原理.先对n分解质因数,分别记录每个质因数, 那么所求区间内与某个质因数不互质的个数就是 m/r(i),假设r(i)是r的某个质因子 假设只有三个质因子, 总的不互质的个数应该为p1+p2+p3-p1*p2-p1*p3-p2*p3+p1*p2*p3. pi代表m/r(i),即与某个质因子不互质的

容斥原理

对容斥原理的描述 容斥原理是一种重要的组合数学方法,可以让你求解任意大小的集合,或者计算复合事件的概率. 描述 容斥原理可以描述如下: 要计算几个集合并集的大小,我们要先将所有单个集合的大小计算出来,然后减去所有两个集合相交的部分,再加回所有三个集合相交的部分,再减去所有四个集合相交的部分,依此类推,一直计算到所有集合相交的部分. 关于集合的原理公式 上述描述的公式形式可以表示如下:                  它可以写得更简洁一些,我们将B作为所有Ai的集合,那么容斥原理就变成了: 这个

【转载】【容斥原理】

转载自 http://www.cppblog.com/vici/archive/2011/09/05/155103.html 容斥原理(翻译) 前言: 这篇文章发表于http://e-maxx.ru/algo/inclusion_exclusion_principle,原文是俄语的.由于文章确实很实用,而且鉴于国内俄文资料翻译的匮乏,我下决心将其翻译之.由于俄语对我来说如同乱码,而用Google直接翻译中文的话又变得面目全非,所以只能先用Google翻译成英语,再反复读,慢慢理解英语的意思,实在

HDU 4336 容斥原理 || 状压DP

状压DP :F(S)=Sum*F(S)+p(x1)*F(S^(1<<x1))+p(x2)*F(S^(1<<x2))...+1; F(S)表示取状态为S的牌的期望次数,Sum表示什么都不取得概率,p(x1)表示的是取x1的概率,最后要加一因为有又多拿了一次.整理一下就可以了. 1 #include <cstdio> 2 const int Maxn=23; 3 double F[1<<Maxn],p[Maxn]; 4 int n; 5 int main() 6