HDU 4407 Sum(容斥)

来源:互联网 发布:淘宝卖家屏蔽买家消息 编辑:程序博客网 时间:2024/06/06 02:59

题意:一个长度为n的序列(初始为1, 2, 3, ...n),现在q次操作,操作1:给你L,R, p, 求区间[L, R]中与p互质的数的和;

作2:修改第x个数为c。(n <= 4e5, q <= 1e3)


思路:因为序列是1-n,所以区间求和可以利用容斥,因为q才1000,所以修改可以存起来,查询时暴力更新。


代码:

#include<bits/stdc++.h>using namespace std;typedef long long ll;const int maxn = 4e5+5;int n, q, x, y, num, yz[maxn];ll ans;map<int, int> m;void dfs(int cur, ll fac, int id){    ll tmp1, tmp2;    if(id%2)    {        ll n = y, d = fac;        ans -= (ll)(d+(n/d)*d)*(n/d)/2;        n = x-1;        ans += (ll)(d+(n/d)*d)*(n/d)/2;    }    else    {        ll n = y, d = fac;        ans += (ll)(d+(n/d)*d)*(n/d)/2;        n = x-1;        ans -= (ll)(d+(n/d)*d)*(n/d)/2;    }    for(int i = cur+1; i < num; i++)        dfs(i, fac*yz[i], id+1);}int main(void){    int _;    cin >> _;    while(_--)    {        m.clear();        scanf("%d%d", &n, &q);        while(q--)        {            int cmd, p, c;            scanf("%d%d", &cmd, &x);            if(cmd == 1)            {                scanf("%d%d", &y, &p);                num = 0;               int tt = p;                for(int i = 2; i*i <= tt; i++)                {                    if(tt % i == 0)                    {                        yz[num++] = i;                        while(tt % i == 0) tt /= i;                    }                }                if(tt != 1) yz[num++] = tt;                ans = (ll)(x+y)*(y-x+1)/2;                for(int i = 0; i < num; i++)                    dfs(i, yz[i], 1);                map<int, int>::iterator it;                for(it = m.begin(); it != m.end(); it++)                {                    int fir = it->first;                    int sec = it->second;                    if(fir >= x && fir <= y)                    {                        if(__gcd(fir, p) == 1)                        {                            if(__gcd(sec, p) == 1) ans = ans-fir+sec;                            else ans = ans-fir;                        }                        else                        {                            if(__gcd(sec, p) == 1) ans = ans+sec;                        }                    }                }                printf("%lld\n", ans);            }            else            {                scanf("%d", &c);                m[x] = c;            }        }    }    return 0;}


原创粉丝点击