zoukankan      html  css  js  c++  java
  • 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 ",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; }



  • 相关阅读:
    RxJava开发精要3-向响应式世界问好
    RxJava开发精要2-为什么是Observables?
    RxJava开发精要1-从.NET到RxJava
    为你的应用加速
    Android最佳性能实践(二)——分析内存的使用情况
    Android最佳性能实践(一)——合理管理内存
    Android 性能优化之使用MAT分析内存泄露问题
    给 Android 开发者的 RxJava 详解
    优化 Android 线程和后台任务开发
    资深谷歌安卓工程师对安卓应用开发的建议
  • 原文地址:https://www.cnblogs.com/wgwyanfs/p/7156803.html
Copyright © 2011-2022 走看看