zoukankan      html  css  js  c++  java
  • hdu1695(容斥 or 莫比乌斯反演)

    刚开始看题,想了一会想到了一种容斥的做法。复杂度O( n(3/2) )但是因为题目上说有3000组测试数据,然后吓尿。完全不敢写。 然后想别的方法。

    唉,最近精神有点问题,昨天从打完bc开始想到1点多,没想到什么好的方法,然后躺床上睡不着,迷迷糊糊又好像挺清醒的,大概想到了用莫比乌斯反演的一种解法,初略的证明了一下发现应该是对的,然后才逐渐有困意,大概也快天亮了。。。 这种事发生了好几次了。上次在证明莫比乌斯反演的时候也是想到快5点才想出来。 感觉整个人都不好了。。

    题目: 求在区间[1,b]和[1,d]中各选一个数,使得这两个数的gcd为k,问有多少种选法。

    稍微推理下问题可以变为:在区间[1,b/k]和[1,d/k]中选两个gcd为1的数。

    设b1=b/k,d1=d/k,假设b1<d1 (b1>b1时swap一下就好了)

    F(x) 表示从区间[1,b1/x]和区间[1,d1/x]中任意选两个数,有多少选数的方法,其实就是(b1/x)*(d1/x)了。

    f(y)  表示从区间[1,b1]和区间[1,d1]中选两个数,使得这两个数的gcd为y的所有种选法。

    那么就可以得到:

    F(1)=f(1)+f(2)+...+f(b1)

    F(2)=f(2)+f(4)+...+f( (b1/2)*2 )

    F(3)=f(3)+f(6)+...+f( (b1/3)*3 )

    ...

    F(b1)=f(b1)

    然后莫比乌斯函数miu(n)为最经典的莫比乌斯函数。

    if n== 1

      miu(n)=1

    else

    if n只由不重复的素数构成

    {

      if(不重复的素数个数为偶数) miu(n)=1;

      else miu(n)=-1;

    }

    else 

      miu(n)=0

    //其实这个只要懂了莫比乌斯反演的原理,还是很好理解的。

    有了整个主题思维后,

    f(1)=miu(1)*F(1)+miu(2)*F(2)+...+miu(b1)*F(b1)

    因为F(x)是显而易见的,我当时一直在以往的因子和里面纠结着,以为莫比乌斯只能应用于求因子的积性函数中。其实莫比乌斯的应用远不如此。要用莫比乌斯的关键是如何找到一个很容易得到F(X)。

    得到了f(1)之后还需要去重复,这个就好弄多了。

    得到1-b1中所有数的欧拉函数之和sum,f(1)-sum+1即为最后的答案。

    详细的见代码:

    //
    //  main.cpp
    //  hdu1695
    //
    //  Created by 陈加寿 on 15/12/13.
    //  Copyright (c) 2015年 陈加寿. All rights reserved.
    //
    
    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <stdlib.h>
    using namespace std;
    #define N 100100
    
    int miu[N];
    long long sum[N];
    
    
    int phi[N];
    void getphis(int maxn)
    {
        phi[1]=1;
        phi[2]=1;
        for(int i=2;i<=maxn;i++) phi[i]=i;
        for(int i=2;i<=maxn;i+=2) phi[i]/=2;
        for(int i=3;i<=maxn;i+=2)
        {
            if(phi[i]==i)//为素数
            {
                for(int j=i;j<=maxn;j+=i)
                {
                    phi[j]=phi[j]-phi[j]/i;
                    
                }
            }
        }
    }
    
    int main() {
        miu[1]=1;
        for(int i=2;i<N;i++)
        {
            int ti=i;
            int tcnt=0;
            for(int j=2;j*j<=ti;j++)
            {
                if(ti%j==0)
                {
                    ti/=j;
                    tcnt++;
                    if(ti%j==0)
                    {
                        tcnt=-1;
                        miu[ i ]=0;
                        break;
                    }
                }
            }
            if(tcnt!=-1)
            {
                if(ti>1)
                {
                    tcnt++;
                }
                miu[i] = tcnt%2==0?1:-1;
            }
        }
        getphis(N-1);
        sum[0]=0;
        for(int i=1;i<N;i++)
            sum[i] += sum[i-1]+phi[i];
        
        int tt=1;
        int T;
        cin>>T;
        while(T--)
        {
            int a,b,c,d,k;
            scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
            printf("Case %d: ",tt++);
            if(k==0)
            {
                //这个是什么鬼。
                printf("0
    ");
                continue;
            }
            
            b/=k;
            d/=k;
            
            
            if(b==0 || d==0)
            {
                printf("0
    ");
                continue;
            }
            if(b>d) swap(b,d);
            long long ans=0;
            for(int i=1;i<=b;i++)
            {
                ans += miu[i]*( (long long)(b/i)*(d/i) );
            }
            ans -= sum[b];
            cout<<ans+1<<endl;
        }
        return 0;
    }

    GCD

    Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 8094    Accepted Submission(s): 3017


    Problem Description
    Given 5 integers: a, b, c, d, k, you're to find x in a...b, y in c...d that GCD(x, y) = k. GCD(x, y) means the greatest common divisor of x and y. Since the number of choices may be very large, you're only required to output the total number of different number pairs.
    Please notice that, (x=5, y=7) and (x=7, y=5) are considered to be the same.

    Yoiu can assume that a = c = 1 in all test cases.
     
    Input
    The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 3,000 cases.
    Each case contains five integers: a, b, c, d, k, 0 < a <= b <= 100,000, 0 < c <= d <= 100,000, 0 <= k <= 100,000, as described above.
     
    Output
    For each test case, print the number of choices. Use the format in the example.
     
    Sample Input
    2 1 3 1 5 1 1 11014 1 14409 9
     
    Sample Output
    Case 1: 9 Case 2: 736427
    Hint
    For the first sample input, all the 9 pairs of numbers are (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 5), (3, 4), (3, 5).
     
    Source
     
  • 相关阅读:
    Unix / 类 Unix shell 中有哪些很酷很冷门很少用很有用的命令?(转)
    5分钟用Spring4 搭建一个REST WebService(转)
    一本好看的书————《反欺骗的艺术——世界传奇黑客的经历分享》
    国内外从事CV相关的企业
    定积分解法
    c++中&amp;和&amp;&amp;有什么差别
    树莓派相关-树莓派串口配置方法
    Linux下df与du两个命令的差别?
    veridata实验举例(2)验证表BONUS与表SALGRADE两节点同步情况
    Java替代C语言的可能性
  • 原文地址:https://www.cnblogs.com/chenhuan001/p/5042945.html
Copyright © 2011-2022 走看看