1. 程式人生 > >BZOJ-1257-[CQOI2007]余數之和sum

BZOJ-1257-[CQOI2007]余數之和sum

none fin tput 復雜 print fad pan sample 出現

Description

給出正整數n和k,計算j(n, k)=k mod 1 + k mod 2 + k mod 3 + … + k mod n的值,其中k mod i表示k除以i的余數。例如j(5, 3)=3 mod 1 + 3 mod 2 + 3 mod 3 + 3 mod 4 + 3 mod 5=0+1+0+3+3=7

Input

輸入僅一行,包含兩個整數n, k。

Output

輸出僅一行,即j(n, k)。

Sample Input

5 3

Sample Output

7

HINT

50%的數據滿足:1<=n, k<=1000 100%的數據滿足:1<=n ,k<=10^9

題解

這道題看了我挺久的

我們可以把k%x轉化成k-[k/x]*x

不考慮上限為n的情況 我們假設[k/x]=a(a>0),那麽x的區間的head就是[k/(a+1)]+1,tail就是[k/a]

這樣我們可以通過求取這一段區間的值(就是等差數列),求出這段區間的k%x的值

a每次改成[k/(head-1)]

head和tail隨之改變

這樣依次做下去直到head變為1

這樣時間復雜度就是a的個數 O(√k)

但是如果x>k呢 實際上x>k的情況只可能在n>k的時候出現

a開始的值為[k/n]=0,head和tail剛開始的值分別[k/(0+1)]+1和n,發現是正確的

技術分享
 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 ll n,k,ans,sum,h,t,num,cnt;
 5 int main(){
 6     scanf("%lld%lld",&n,&k);
 7     cnt=k/n;
 8     t=n;
 9     h=k/(cnt+1)+1;
10     ans+=k*(t-h+1)-cnt*(t-h+1)*(t+h)/2;
11     while (h>1){
12         cnt=k/(h-1
); 13 t=k/cnt; 14 h=k/(cnt+1)+1; 15 ans+=k*(t-h+1)-cnt*(t-h+1)*(t+h)/2; 16 } 17 printf("%lld\n",ans); 18 return 0; 19 }
View Code

BZOJ-1257-[CQOI2007]余數之和sum