hdu4407 Sum (容斥)

题目连锁 :http://acm.hdu.edu.cn/showproblem.php?pid=4407


第一种操作 求x到y之间与p互质的数之和,容斥原理,求出不互质的数,减去就可以(remem)

第二种操作 把x改为y


#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<stdio.h>
#include<algorithm>
#include<cmath>
#include<set>
#include<map>
#include<queue>
using namespace std;


#define inf 0x3f3f3f3f
#define eps 1e-9
#define mod 10007
#define FOR(i,s,t) for(int i = s; i < t; ++i )
#define REP(i,s,t) for( int i = s; i <= t; ++i )
#define LL unsigned long long
#define ULL unsigned long long
#define pii pair<int,int>
#define MP make_pair
#define lson id << 1 , l , m
#define rson id << 1 | 1 , m + 1 , r 
#define maxn ( 400000+100 )
#define maxe ( 1000000+10 )
#define mxn 20000

bool isnot[maxn];
int prime[maxn], num;

void get_prime() { //欧拉帅法
    isnot[0] = isnot[1] = 1;
    for( int i = 2; i <= maxn; ++i ) {
        if( !isnot[i] ) prime[num++] = i;
        for( int j = 0; j < num && prime[j] * i < maxn; ++j ) {
            isnot[i*prime[j]] = 1;
            if( i % prime[j] == 0 ) break;
        }
    }
}

int p;
int fac[maxn], cnt;

void div( int x ) {  //获取质因数
    cnt = 0;
    for( int i = 0; prime[i] * prime[i] <= x; ++i ) {
        if( x % prime[i] == 0 ) {
            while( x % prime[i] == 0 ) x /= prime[i];
            fac[cnt++] = prime[i];
        }
    }
    if( x != 1 ) fac[cnt++] = x;
}

LL ans;
void dfs ( int id, int c, LL num, int tot, int n ) {
    if( c == tot ) {
        LL k = n /  num;
        if( c & 1 ) ans -= num * ( 1 + k ) * k / 2;
        else ans += num * ( 1 + k ) * k / 2;
        return ;
    }
    if( num > n || id >= cnt || c > tot ) return ;
    dfs ( id + 1, c, num, tot, n );
    dfs ( id + 1, c + 1, num * fac[id], tot, n );
}

LL solve( int n ) {
    ans = (LL)(1+n)*n/2;
    for( int i = 1; i <= cnt; ++i ) 
        dfs( 0, 0, 1, i, n );
    return ans;
}

map< int , int > mp;
map<int , int > :: iterator it;

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

int main () {
    int T;
    //freopen( "in.in", "r", stdin );
    get_prime();
    scanf("%d", &T );
    while( T-- ) {
        int n, m;
        scanf("%d%d", &n, &m );
        mp.clear();
        int op, x, y;
        while( m-- ) {
            scanf("%d", &op );
            if ( op == 1 ) {
                scanf("%d%d%d", &x, &y, &p );
                div( p );
                LL res = solve( y ) - solve( x-1 );
                for( it = mp.begin(); it != mp.end(); ++it ) {
                    if( it->first < x || it->first > y ) continue;
                    if( gcd( it->first, p ) == 1 ) res -= it->first;
                    if( gcd( it->second, p ) == 1 ) res += it->second;
                }
                printf("%lld\n", res);
            }
            else {
                scanf("%d%d", &x, &y );
                mp[x] = y;
            }
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值