1. 程式人生 > >P2261 [CQOI2007]余數求和

P2261 [CQOI2007]余數求和

輸入 ans 正整數 DC 取模 fine -c 輸出格式 序列

題目背景

數學題,無背景

題目描述

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

輸入輸出格式

輸入格式:

兩個整數n k

輸出格式:

答案

輸入輸出樣例

輸入樣例#1:
10 5
輸出樣例#1:
29

說明

30%: n,k <= 1000

60%: n,k <= 10^6

100% n,k <= 10^9

Solution:

  本題$zyys$的數論分塊。

  類似於$Ahoi$約數研究的思路。

  首先,對取模式子化簡得:$k\;mod\;i=k-i\times\lfloor{k/i}\rfloor$。

  所以最後的$ans=\sum\limits_{i=1}^{n}{(k-i\times\lfloor{k/i}\rfloor)}=n\times k-\sum\limits_{i=1}^{n}{i\times\lfloor{k/i}\rfloor}$

  對於$i\times\lfloor{k/i}\rfloor$中,$\lfloor{k/i}\rfloor$有許多是相同的,假設$x=\lfloor{k/i}\rfloor$($i$為第一次出現$x$值的下標),則$i_{max}=\lfloor{k/x}\rfloor$,從$i$到$i_{max}$共有$i_{max}-i+1$個$x$。

  註意到$i\times\lfloor{k/i}\rfloor$中還有系數$i$,而$i$到$i_{max}$是遞增的(每次加$1$),所以是一個公差為$x$的等差序列,直接套上等差數列求和公式即可。

  因為$i\leq n$且$\lfloor{k/i}\rfloor$可能為$0$,所以記得判斷邊界。

  由於$\lfloor{k/i}\rfloor$的值最多有$2\times\sqrt{n}$個,所以時間復雜度為$O(\sqrt{n})$。

代碼:

 1 #include<bits/stdc++.h>
 2 #define il inline
 3 #define ll long long
 4 #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
 5 #define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
 6 #define Max(a,b) ((a)>(b)?(a):(b))
 7 #define Min(a,b) ((a)>(b)?(b):(a))
 8 using namespace std;
 9 ll ans=0,n,k;
10 
11 int main(){
12     ios::sync_with_stdio(0);
13     cin>>n>>k;
14     int p;
15     ans=n*k;
16     for(ll i=1;i<=n;i=p+1){
17         p=(k/i?Min(k/(k/i),n):n);
18         ans-=(k/i)*(i+p)*(p-i+1)/2;
19     }
20     cout<<ans;
21     return 0;
22 }

P2261 [CQOI2007]余數求和