HDU 1695 GCD (容斥 + 莫比烏斯反演)

_TCgogogo_發表於2015-08-16

GCD

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 7450    Accepted Submission(s): 2731

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
 
題目大意:尼瑪,還特地補了句a=1,c=1。。。就是求從[1,b]和[1,d]中選出的二元組的最大公約數為k的組數,這裡(a,b)和(b,a)算一種


題目分析:HDU的資料太水了,這題用分塊求和優化和不做優化跑出來都是15ms,類似BZOJ 2301,比那個簡單,不過比那個坑多了,不懂這個k為什麼要從0開始。。。特判答案為0兩種情況,一個是k=0,另一個是max(b, d) < k,把區間化成(1, b/k),(1, d/k),就是求兩個區間各取出一個數使它們gcd為1的個數,剩下來的用莫比烏斯反演求就行了,然後就是這題的(a,b)和(b,a)算一種,因此要去重,方法很簡單,比如第一個樣例,區間1 5包含了1 3,因此要減去重複的部分,重複的部分就是cal(3, 3) / 2了,最後要用long long,算了下,極限資料答案是3e9左右,就超這麼一點點,還真看不出來。。。


#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
int const MAX = 1e5 + 5;
int mob[MAX], p[MAX], sum[MAX];
bool prime[MAX];

void Mobius()
{
    int pnum = 0;
    memset(sum, 0, sizeof(sum));
    memset(prime, true, sizeof(prime));
    mob[1] = 1;
    sum[1] = 1;
    for(int i = 2; i < MAX; i++)
    {
        if(prime[i])
        {
            p[pnum ++] = i;
            mob[i] = -1;
        }
        for(int j = 0; j < pnum && i * p[j] < MAX; j++)
        {
            prime[i * p[j]] = false;
            if(i % p[j] == 0)   
            {
                mob[i * p[j]] = 0;
                break;
            } 
            mob[i * p[j]] = -mob[i];
        }
        sum[i] = sum[i - 1] + mob[i];
    }
}

ll cal(int l, int r)
{
    if(l > r)
        swap(l, r);
    ll ans = 0;
    for(int i = 1, last = 0; i <= l; i = last + 1)
    {
        last = min(l / (l / i), r / (r / i));
        ans += (ll) (l / i) * (r / i) * (sum[last] - sum[i - 1]);
    }
    return ans;
}

int main()
{
    Mobius();
    int T;
    scanf("%d", &T);
    for(int ca = 1; ca <= T; ca++)
    {
        int a, b, c, d, k;
        scanf("%d %d %d %d %d", &a, &b, &c, &d, &k);
        if(k == 0 || max(b, d) < k)
        {
            printf("Case %d: 0\n", ca);
            continue;
        }
        int mi = min(b / k, d / k);
        printf("Case %d: %I64d\n", ca, cal(b / k, d / k) - cal(mi, mi) / 2);
    }
}


相關文章