題目描述
G. 2017
Given a, b, c, d, find out the number of pairs of integers (x, y) where a ≤ x ≤ b, c ≤ y ≤ d and x · y is multiple of 2017.
Input
The input contains zero or more test cases and is terminated by end-of-file.
Each test case contains four integers a, b, c, d.
• 1 ≤ a ≤ b ≤ 109 , 1 ≤ c ≤ d ≤ 109
• The number of tests cases does not exceed 104
Output
For each case, output an integer which denotes the result.
Sample Input
1 2017 1 2016
1 1000000000 1 1000000000
Sample Output
2016
991324197233775
題意分析
從題目描述中可以很輕易的讀懂(英語渣 _ ),就是給定區間 [ a , b ] , [ c , d ] , 然後分別在兩個區間中各找一個數 x , y , 要求 x 屬於第一個區間, y 屬於第二個區間,並且 x * y 是2017的倍數。
拿到這道題目的時候其實我是很開心的,畢竟分析了下就有了思路(畢竟大家都說是水題噠)
解題分析
首先,2017是一個素數,那麼要想 x * y 是2017的倍數,x , y 必定存在至少一個數是2017的倍數
當選定了一個數,假定是 x , 那麼 y 無論何值都滿足條件(注意 a b c d 的範圍都是1 到1e9)
對於一個區間中,找出2017的倍數,第一種方法是篩法求,其實這種方法效率已經很高了。不過還有更爲高效的方法:就 [ a , b ] 區間來說,令 m = b/2017, n = a/2017 , 很顯然,m - n在大多數情況下就能直接得到此區間中2017的倍數有多少個,但是注意,當 a 也是2017的倍數的時候,應爲 m - n + 1 (此點也是一直卡住我的地方,當時想到了會多一個,但是在判斷是否 +1 的這個條件的時候,誤以爲是隻要 a/2017不爲0時則加1,從而導致WA,心累呀)
由上邊得到了 m 和 n 後,我們能夠得到 m*len2(第二個區間的長度),n*len1(第一個區間的長度)之和則爲所有的可能數,但是在這樣的情況下,我們會發現我們有可能會存在多加的情況,當兩個區間有交集並且交集中存在2017的倍數的情況下,此時我們會多加一定的可能數,那麼我們如何去解決這種情況呢?
第一種方法:既然我們已經算出了 m*len2 + n*len1, 那麼我們只需要減去對應的重複項即可,即查找出兩個區間中重複的2017的倍數項的個數 x,那麼結果即爲 res = m*len2 + n*len1 - x*x
第二種方法:我們逆向思考,我們需要的是符合條件的,那麼是不是總數 - 不符合條件數即可呢?我們想下,題目中的總數即爲len1 * len2 , 不符合條件的即爲 (len1 - m) * (len2 - n) ,那麼結果 res = len1 * len2 - (len1 - m) * (len2 - n)
AC代碼
#include <bits/stdc++.h>
using namespace std;
int main(){
long long a,b,c,d;
while(cin>>a>>b>>c>>d){
long long len1 = b-a+1;
long long len2 = d-c+1;
long long m= 0 ,n=0;
m = b/2017 - a/2017;
if(a%2017 == 0){
m++;
}
n = d/2017 - c/2017;
if(c%2017 == 0){
n++;
}
unsigned long long res = 0;
res = len1*len2 - (len1-m)*(len2-n);
cout<<res<<endl;
}
return 0;
}
注:
如有錯誤,歡迎dalao評論指正
.