现在的位置: 首页 > 综合 > 正文

HDU 4407 SUM 【数论,容斥原理】

2013年10月06日 ⁄ 综合 ⁄ 共 1399字 ⁄ 字号 评论关闭

这道题目用到的知识和
【HDU 1695 GCD】
是一样的。

都可以抽象出一个子问题:判断一个数s同区间(x, y)里面有多少个数互素——用容斥原理可以解决。

这道题目不是统计互素的个数,而是统计与s互素的数的和,其实没有区别,求出个数之后等差数列求和就可以。

还有一个修改操作:由于修改的次数不是很多,可以单独考虑更改的数字——注意判重(代码中有注释)


#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
#define N 400010
typedef long long LL;

int n, m;
struct node {
    int idx, v;
    node() {}
    node(int x, int y): idx(x), v(y) {}
};
vector<node> c;
bool is[N];
vector<int> pr;
void prime() {
    memset(is, true, sizeof(is));
    pr.clear();
    pr.push_back(2);
    for (int i=3; i<N; i+=2)
        if (is[i]) {
            pr.push_back(i);
            for (int j=i+i; j<N; j+=i) is[j] = false;
        }
}
LL cal(int x, int p, vector<int> &g) {
    LL ret = (LL)x*(x+1)/2;

    for (int s=1; s<(1<<g.size()); s++) {
        int cnt = 0;
        int v = 1;
        for (int i=0; i<g.size(); i++)
            if (s & (1<<i)) {
                cnt++;
                v *= g[i];
            }


        LL k = x / v;
        k = k*(k+1)*v/2;
        if (cnt % 2 == 1) ret -= k;
        else ret += k;
    }

    for (int i=0; i<c.size(); i++)
        if (c[i].idx <= x) {
            if (__gcd(c[i].idx, p) == 1)ret -= c[i].idx;
            if (__gcd(c[i].v, p) == 1) ret += c[i].v;
        }
    return ret;
}
void work(int x, int y, int p) {
    vector<int> g;
    int k = p;
    for (int i=0; i<pr.size() && pr[i]<=k; i++)
        if (k % pr[i] == 0) {
            g.push_back(pr[i]);
            while (k % pr[i] == 0) k /= pr[i];
        }

    printf("%I64d\n", cal(y, p, g)-cal(x-1, p, g));
}
int main() {

    prime();

    int T, x, y, o, p;
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d", &n, &m);
        c.clear();
        while (m--) {
            scanf("%d", &o);
            if (o == 1) {
                scanf("%d%d%d", &x, &y, &p);
                work(x, y, p);
            } else {
                scanf("%d%d", &x, &y);
                //判断当前位置x是不是已经被修改过,判重
                bool f = true;
                for (int i=0; i<c.size(); i++)
                    if (c[i].idx == x) {
                        c[i].v = y;
                        f = false; break;
                    }
                if (f) c.push_back(node(x, y));
            }
        }
    }
    return 0;
}

抱歉!评论已关闭.