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

[CQOI2007]餘數求和

題目連結:[CQOI2007]餘數求和

題意:求$\sum_{i=1}^{n}k\ mod \ i$

式子的變形比較常規

$$\sum_{i=1}^{n}k\ mod \ i=\sum_{i=1}^{n}{(k-\lfloor{\frac{k}{i}}\rfloor *i)}=k*n-\sum_{i=1}^n{\lfloor{\frac{k}{i}\rfloor}*i}$$

注意到$\lfloor{\frac{k}{i}\rfloor}$的取值程階梯狀遞增,一共有$\sqrt{n}$種取值可以使用

所以如果我們能將所有$\lfloor \frac{k}{i}\rfloor$相同的數一起處理的話,時間複雜度就約為$O(\sqrt n)$,可以承受

那麼問題就是如何找到這些相同的數了,很明顯它們會處在一段區間中

所以只要找到區間的兩個端點就可以了

即找到能使$\lfloor\frac{k}{i}\rfloor==\lfloor\frac{k}{j}\rfloor$成立的最大的$j$

打表發現$j=\lfloor\frac{k}{\lfloor{\frac{k}{i}\rfloor}}\rfloor$

那麼考慮如何證明它

先證明當$j=\lfloor\frac{k}{\lfloor{\frac{k}{i}\rfloor}}\rfloor$時結論成立

$\because \lfloor\frac{k}{i}\rfloor \leq \frac{k}{i}$

$\therefore \frac{n}{\lfloor{\frac{k}{i}}\rfloor}\geq \frac{k}{\frac{k}{i}}=k$

即$\therefore \frac{n}{\lfloor{\frac{k}{i}}\rfloor}\geq k$

接下來證明,當$j=\lfloor\frac{k}{\lfloor{\frac{k}{i}\rfloor}+1}\rfloor$時結論不成立,即證明$\lfloor\frac{k}{\lfloor{\frac{k}{i}\rfloor}+1}\rfloor<a$(記$a=\lfloor\frac{k}{i}\rfloor$)

由待證不等式知$\frac{k}{\lfloor{\frac{k}{i}\rfloor}+1}<a$

$a*{\lfloor\frac{k}{i}\rfloor}+a>k$

對$k$進行帶餘除法可得$k=qa+r(0\leq r<a)$

$a*{\lfloor\frac{k}{i}\rfloor}+a=a*q+a>qa+r=k$

結論得證

那麼接下來只要對$t=\lfloor\frac{k}{i}\rfloor$分類討論即可

1)若$t\not=0$,則右邊界$r=min(\lfloor\frac{k}{t}\rfloor,n)$(有可能出現$\lfloor\frac{k}{t}\rfloor>n$的情況,比如k很大,這時候不要超出邊界)

2)若$t=0$,則右邊界$r=n$(此時後面的所有數必然可以保證都>k,那麼說明後面的所有數都屬於同一部分)

程式碼

 1 #include<iostream>
 2 #include<string>
 3 #include<string.h>
 4 #include<stdio.h>
 5 #include<algorithm>
 6 using namespace std;
 7 int main()
 8 {
 9     long long n,k;
10     scanf("%lld%lld",&n,&k);
11     long long ans=n*k,l=1,r;
12     while (l<=n)
13 { 14 if (k/l==0) r=n; else r=min(n,k/(k/l)); 15 ans-=(k/l)*(l+r)*(r-l+1)/2; 16 l=r+1; 17 } 18 printf("%lld",ans); 19 return 0; 20 } 21