hdu 4407 Sum 容斥原理

题意很简单,就是给你一个数组大小为n的值从1到n,之后有m次操作,要么修改前面的数组中的某一项,要么是输出从x到y(包括边界)中的数与p互质的数的和。由于m很小(m<=1000)故,将修改的部分保存下来之后统计输出时,在判断修改的部分是否与p互质,若是要修改原来的,在修改现在的。

注意,就是多次修改同一个地方,只记录最后一次。

对于统计从x到y的与p互质数的和,有结果=数1到y的满足要求的结果-数1到x-1的满足要求的结果。

而从1开始到n的数中与p互质的数的和的求法,就是个容斥原理的算法。

剔除p中单个素因子的倍数,加上两个因子的倍数,接着在剔除三个素因子的倍数,直到所有的素因子结束。

。/**   

 * @Title: HDU4407.java 

 * @Package com.wangzhu.hdu 

 * @Description: TODO

 * @author 王竹

 * @date 2012-9-22 下午7:40:27 

 * @version V1.0   

 *

 */

package com.wangzhu.hdu;



import java.io.BufferedInputStream;

import java.util.Arrays;

import java.util.Scanner;



/**

 * @ClassName: HDU4407

 * @Description: TODO

 * @author 王竹

 * @date 2012-9-22 下午7:40:27

 * 

 */

public class HDU4407 {



    public static void main(String[] args) {

        // System.setIn(new FileInputStream("data.in"));

        Scanner cin = new Scanner(new BufferedInputStream(System.in));

        int t, n, m, cas, x, y, c, p;

        initPrime();

        while (cin.hasNext()) {

            t = cin.nextInt();

            while (t-- > 0) {

                n = cin.nextInt();

                m = cin.nextInt();

                node = new Node[m + 1];

                lastIndex = new int[MAXN];

                nodeLen = 0;

                for (int i = 0; i < m; i++) {

                    cas = cin.nextInt();

                    if (cas == 2) {

                        x = cin.nextInt();

                        c = cin.nextInt();

                        node[nodeLen] = new Node(x, c);

                        lastIndex[x] = nodeLen++;

                    } else {

                        x = cin.nextInt();

                        y = cin.nextInt();

                        p = cin.nextInt();

                        work(x, y, p, n);



                    }

                }

            }

        }

        cin.close();

    }



    private final static int MAXN = 400001;

    static int[] lastIndex;

    private final static int VAL = 1000;

    static int[] prime = new int[VAL];

    static boolean[] isPrime = new boolean[VAL];

    static int primeLen;



    public static void initPrime() {

        Arrays.fill(isPrime, false);

        primeLen = 0;

        prime[primeLen++] = 2;

        for (int i = 4; i < VAL; i += 2) {

            isPrime[i] = true;

        }

        for (int i = 3; i < VAL; i += 2) {

            if (!isPrime[i]) {

                prime[primeLen++] = i;

            }

            for (int j = 0; (j < primeLen) && (i * prime[j] < VAL); j++) {

                isPrime[i * prime[j]] = true;

                if (i % prime[j] == 0) {

                    break;

                }

            }

        }

    }



    static Node[] node;

    static int nodeLen;



    static int[] primeFactor; // 存储素因子

    static int primeFactorLen;



    /**

     * 分解数p获得其素因子

     * 

     * @param p

     */

    public static void mkPrimeFactor(int p) {

        primeFactor = new int[VAL];

        int temp = (int) Math.sqrt(1.0 * p);

        primeFactorLen = 0;

        for (int i = 0; (i < primeLen) && (prime[i] <= temp); i++) {

            if (p % prime[i] == 0) {

                primeFactor[primeFactorLen++] = prime[i];

                while (p % prime[i] == 0) {

                    p /= prime[i];

                }

            }

        }

        if (p > 1) {

            primeFactor[primeFactorLen++] = p;

        }

    }



    private static void work(int x, int y, int p, int n) {

        mkPrimeFactor(p);

        long res = getSum(y) - getSum(x - 1);

        for (int i = 0; i < nodeLen; i++) {

            if (node[i].x >= x && node[i].x <= y) {

                // 若是多次修改同一个地方,则只取最后一次

                if (i != lastIndex[node[i].x]) {

                    continue;

                }

                if (isCoPrime(node[i].x, p)) {

                    res -= node[i].x;

                }

                if (isCoPrime(node[i].c, p)) {

                    res += node[i].c;

                }

            }

        }

        System.out.println(res);

    }



    private static long getSum(int i) {

        long res = (long) i * (i + 1) / 2;

        res -= dfs(0, i, 1);

        return res;

    }



    private static boolean isCoPrime(int c, int p) {

        return gcd(c, p) == 1;

    }



    /**

     * 最大公约数

     * 

     * @param a

     * @param b

     * @return

     */

    public static long gcd(long a, long b) {

        long r;

        if (a < b) {

            r = a;

            a = b;

            b = r;

        }

        while (b != 0) {

            r = a % b;

            a = b;

            b = r;

        }

        return a;

    }



    /**

     * 容斥原理 获得在n下所有与p互质的数的和

     * 

     * @param start

     * @param n

     * @param now

     * @return

     */

    private static long dfs(int start, int n, long now) {

        long res = 0, temp;

        for (int i = start; i < primeFactorLen; i++) {

            temp = lcm(now, primeFactor[i]);// 每一个开始,之后就是其最小公倍数

            res += getPrimeSum(temp, n) - dfs(i + 1, n, temp);

        }

        return res;

    }



    /**

     * 最小公倍数

     * 

     * @param now

     * @param i

     * @return

     */

    private static long lcm(long now, long i) {

        return (long) now / gcd(now, i) * i;

    }



    private static long getPrimeSum(long num, int n) {

        long temp = n / num;

        return temp * (temp + 1) / 2 * num;

    }



}



class Node {

    int x;

    int c;



    public Node(int x, int c) {

        this.x = x;

        this.c = c;

    }

}

 

 

你可能感兴趣的:(HDU)