码迷,mamicode.com
首页 > 其他好文 > 详细

HDU4407 Sum【容斥原理】

时间:2015-08-13 18:07:39      阅读:83      评论:0      收藏:0      [点我收藏+]

标签:

题目链接:

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;
}


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

HDU4407 Sum【容斥原理】

标签:

原文地址:http://blog.csdn.net/lianai911/article/details/47614819

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!