• hdu 1695 GCD 容斥原理 ural 1091


    以下转自于:

    http://blog.sina.com.cn/s/blog_59e67e2c0100a84o.html

    题目意思不难已知给定k,x,y求 1<=a<=x 1<=b<=y 中满足 gcd(a,b)=k 的(a,b)对数。(注意数对是无序的)。 1<=x,y<=10w, 0<=k<=10w

     

     题目有比较恶心的一点,数据有k==0的,这时显然答案是0,没有2个数的gcd为0。

     首先,gcd是没啥用的。因为约掉gcd后两个数互质。于是我们可以让x/=k y/=k并且假设 x<=y

     然后题目变成了 2个数分别在区间[1..x]和[1..y]中的互质数有多少对。

     大体思路:

         枚举[1..y]中每个数i 判断[1..min(x,i)]中有多少数与i互质,统计个数。(注意,枚举的是比较大的区间[1..y])。

         显然如果i是质数,则[1..min(x,i)]中与i互质的个数是全体的个数或者i-1个。(取决于x和i的大小)。

         当i不是质数时,i分解质因数后,质因数的次数不影响结果。我们看另外那个区间有多少个和i不互质(减一下就好了),于是我们只要看另外那个区间中有多少个数是i质因数的倍数就好了。

         区间[1..w]中 p的倍数 显然有 w/p个。

         我们枚举i的质因数利用容斥原理:

              看另外那个区间有多少个数与i不互质。

              容斥原理的具体如下:

              区间中与i不互质的个数 = (区间中i的每个质因数的倍数个数)-(区间中i的每两个质因数乘积的倍数)+(区间中i的每3个质因数的成绩的倍数个数)-(区间中i的每4个质因数的乘积)+...

              于是问题变成了统计每个数的不同质因数的个数而忽略次数。这个可以用筛法。具体做法如下:

              对每个数保存一个真质因数的列表。初始每个列表的长度为0。然后从2开始,分别检查每个数的列表长度,如果列表长度不为0,则这个数是合数,跳过;如果这个长度为0,则我们找到了一个质数,同时再把这个数的倍数(不包含本身)的列表里加入这个数。

               这样筛一次下来,我们保存了每个数的真质因数列表,问题得到解决,还要注意结果用要用__int64。

    /*
    * hdu1695.c
    *
    * Created on: 2011-10-3
    * Author: bjfuwangzhu
    */

    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #define LL long long
    #define nmax 100010
    int prime[nmax], phi[nmax], pfactor[nmax], cpfactor[nmax];
    int plen, pflen;
    void init() {
    int i, j;
    memset(phi, 0, sizeof(phi));
    phi[0] = 0, phi[1] = 1;
    for (i = 2, plen = 0; i < nmax; i++) {
    if (!phi[i]) {
    phi[i] = i - 1;
    prime[plen++] = i;
    }
    for (j = 0; (j < plen) && (i * prime[j] < nmax); j++) {
    if (i % prime[j] == 0) {
    phi[i * prime[j]] = phi[i] * prime[j];
    break;
    } else {
    phi[i * prime[j]] = phi[i] * (prime[j] - 1);
    }
    }
    }
    }
    void getpFactor(int n) {
    int i, te;
    te = (int) sqrt(n * 1.0);
    for (i = 0, pflen = 0; (i < plen) && (prime[i] <= te); i++) {
    if (n % prime[i] == 0) {
    cpfactor[pflen] = 0;
    while (n % prime[i] == 0) {
    n /= prime[i];
    cpfactor[pflen]++;
    }
    pfactor[pflen++] = prime[i];
    }
    }
    if (n > 1) {
    cpfactor[pflen] = 1;
    pfactor[pflen++] = n;
    }
    }
    LL dfs(int n, int start) {
    int i;
    LL res;
    for (i = start, res = 0; i < pflen; i++) {
    res += n / pfactor[i] - dfs(n / pfactor[i], i + 1);
    }
    return res;
    }
    int main() {
    #ifndef ONLINE_JUDGE
    freopen("data.in", "r", stdin);
    #endif
    int t, i, j, a, b, c, d, k;
    LL res;
    init();
    scanf("%d", &t);
    for (i = 1; i <= t; i++) {
    scanf("%d %d %d %d %d", &a, &b, &c, &d, &k);
    b /= a, d /= c;
    if (k == 0 || k > b || k > d) {
    res = 0;
    } else {
    b /= k, d /= k;
    if (b > d) {
    b ^= d, d ^= b, b ^= d;
    }
    for (j = 1, res = 0; j <= b; j++) {
    res += phi[j];
    }
    for (j = b + 1; j <= d; j++) {
    getpFactor(j);
    res += b - dfs(b, 0);
    }
    }
    printf("Case %d: %I64d\n", i, res);
    }
    return 0;
    }


    ural 1091. Tmutarakan Exams

    http://acm.timus.ru/problem.aspx?space=1&num=1091

    /*
    * timus1091.c
    *
    * Created on: 2011-10-6
    * Author: bjfuwangzhu
    */

    #include<stdio.h>
    #define pnum 15
    #define nmax 10000
    int prime[pnum] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47 };
    int mark;
    int solve(int n, int k, int m) {
    int te, i, res;
    te = n / m;
    if (k > te) {
    return 0;
    }
    if (k > te / 2) {
    k = te - k;
    }
    for (i = 0, res = 1; i < k; i++) {
    res = res * (te - i) / (i + 1);
    if (res >= nmax) {
    return -1;
    }
    }
    return res;
    }
    int dfs(int start, int s, int k) {
    int i, res, temp;
    for (i = start, res = 0; (i < pnum) && (prime[i] <= s); i++) {
    temp = solve(s, k, prime[i]);
    if (temp == -1) {
    mark = 1;
    return 0;
    } else {
    res += temp - dfs(i + 1, s / prime[i], k);
    }
    if (res >= nmax) {
    mark = 1;
    return 0;
    }
    }
    return res;
    }
    int main() {
    #ifndef ONLINE_JUDGE
    freopen("data.in", "r", stdin);
    #endif
    int k, s, res;
    while (~scanf("%d %d", &k, &s)) {
    mark = 0;
    res = dfs(0, s, k);
    if (mark) {
    res = nmax;
    }
    printf("%d\n", res);
    }
    return 0;
    }

  • 相关阅读:
    ORACLE的主要进程DBWn,LGWR的工作原理
    ORACLE PGA
    如何精确获取ORACLE的秒?
    Dictionary.TryGetValue 方法 试用记 Mark
    在C#中如何实现Form与Form之间的通信
    在建立与服务器的连接时出错。在连接到 SQL Server 2005 时,在默认的设置下 SQL Server 不允许进行远程连接可能会导致此失败。 (provider: 命名管道提供程序, error: 40 无法打开到 SQL Server 的连接)
    在C#程序中实现插件架构
    兄弟,你有弄过TestDriven.NET吗?
    由C#风潮想起的-给初学编程者的忠告
    今天真是不在状态的一天,又是一个书写的错误(本文仅为提醒自己,你可以选择跳过)
  • 原文地址:https://www.cnblogs.com/xiaoxian1369/p/2198579.html
Copyright © 2020-2023  润新知