您的位置:首页 > 其它

HDU 4407 Sum(容斥原理+质因数分解)

2015-08-24 17:29 337 查看

HDU 4407

题意:

给一个长度为n的序列,序列由1~n依次组成。

对序列执行两种操作:

1.查询[x,y]内与p互素的数的和;

2.修改第x数为c.

思路:

往线段树的方向想了半天,发现就是容斥原理略微变形,脑残不可医啊。。

修改操作可以用map进行映射。

查询操作的话我们就把序列一直当做1~n的序列来查询,然后迭代器跑一遍map判断对查询有无影响即可,总之操作最多2000次;

对于查询操作,我们可以先分解出p的质因数,设p的每种质因数组合的里的质因数乘积为value,那么[x,y]内value的倍数与p必定不互素,求出value的区间[x,y]内所有倍数和(用等比数列求和公式),然后对结果进行容斥求和,即得出区间[x,y]内与p不互素的数的和sum,然后区间所有数的和(用等差数列求和公式)减去sum即可。

代码:

[code]/*
* @author FreeWifi_novicer
* language : C++/C
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>

using namespace std;

#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define mp make_pair
#define pb push_back
typedef long long lint;
typedef long long ll;
typedef long long LL;

map<int , int>v ;
vector<int>fac ;

int gcd( int x , int y ){
    if( y == 0 ) return x ;
    return gcd( y , x % y ) ;
}

lint cal( int l , int r , int val ){
    int n = ( r / val ) - ( ( l - 1 ) / val ) ;
    int a1 = ( l % val == 0 )? l : ( val - l % val ) + l ;
    int an = r - r % val ;
    lint res = (lint)( a1 + an ) * (lint)n / 2 ; // 等比数列求和公式
    return res ;
}

lint work( int l , int r , int p ){
    fac.clear() ;
    for( int i = 2 ; i * i <= p ; i++ ){
        if( p % i == 0 ){
            fac.pb( i ) ;
            while( p % i == 0 ) p /= i ;
        }
    }
    if( p > 1 ) fac.pb( p ) ;
    int s = fac.size() ;
    lint res = 0 ;
    for( int i = 1 ; i < ( 1 << s ) ; i++ ){
        int bits = 0 ;
        lint val = 1 ;
        for( lint j = 0 ; j < s ; j++ ){
            if( i & ( 1 << j ) ){
                bits++ ;
                val *= fac[j] ;
            }
        }
        lint tmp = cal( l , r , val ) ;
        if( bits & 1 ) // 容斥原理
            res += tmp ;
        else
            res -= tmp ;
    }
    lint sum =  (lint)( l + r ) * (lint)( r - l + 1 ) / 2 ;
    res = sum - res ; // 等差数列求和公式
    return res ;
}

lint solve( int l , int r , int p ){
    lint res = work( l , r , p ) ;
    if( v.empty() ) return res ;

    map<int,int>::iterator it ;
    for( it = v.begin() ; it != v.end() ; it++ ){
        lint x = it->first , y = it->second ;
        if( x > r || x < l ) continue ;
        if( gcd( x , p ) == 1 ) res -= x ;
        if( gcd( y , p ) == 1 ) res += y ;
    }
    return res ;
}

int main(){
  //freopen("input.txt","r",stdin);
    int t ; cin >> t ;
    while( t-- ){
        v.clear() ;
        int n , m ;
        cin >> n >> m ;
        for( int i = 1 ; i <= m ; i++ ){
            int op ;
            scanf( "%d" , &op ) ;
            if( op == 1 ){
                int l , r , p ;
                scanf( "%d%d%d" , &l , &r , &p ) ;
                if( l > r ) swap( l , r ) ;
                lint ans = solve( l , r , p ) ;
                printf( "%I64d\n" , ans ) ;
            }
            else if( op == 2 ){
                int pos , x ;
                scanf( "%d%d" , &pos , &x ) ;
                v[pos] = x ;
            }
        }
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: