codeforces 616E Sum of Remainders(數學公式轉化 較難)
阿新 • • 發佈:2019-02-19
輸入n,m(1<=n,m<=10^13),求n%1+n%2+n%3+……+n%m,資料結果較大,對10^9+7取餘
n%i ==> n-[n/i]*i
原式化為n*m - ∑i=1m[n/i]∗i
思路1:l=n/(i+1)+1, r=n/i ==> n/x(l<=x<=r)的值必定等於i
舉個例子n=20,m=20,現將n開根號了
i=1 ==> l=11, r=20
i=2 ==> l=7, r=10
i=3 ==>. l=r=6
i=4 ==> l=r=5
那麼還應該求n%1*1,n%2*2,n%3*3,n%4*4
所以程式碼中的las就是標記還剩下幾個沒有取餘
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <string> #include <cmath> using namespace std; #define ll __int64 const ll mod=1e9+7; int main() { ll n, m; scanf("%I64d%I64d", &n, &m); ll ans = (n%mod)*(m%mod)%mod, tmp=0, las=m+1; m = min(m, n); for(ll i=1; i<=(ll)sqrt(n*1.0); i++) { ll l=n/(i+1)+1, r=n/i; r = min(r, m); if(l>r) continue; las = min(las, l); ll s1=l+r, s2=r-l+1; if(s1%2==0) s1/=2; else s2/=2; s1%=mod, s2%=mod; s1 = (s1*s2)%mod; s1 = (s1*i)%mod; tmp = (tmp + s1)%mod; } ans = (ans- tmp +mod )% mod; for(int i=1; i<las; i++) { tmp = n/i%mod*i%mod; ans = (ans- tmp +mod)% mod; } printf("%I64d\n", ans); return 0; }
思路2:l=i, r=n/(n/i) ==> n/x(l<=x<=r)的值必定是i
跟上面的思路是極像的,只不過這種方法並沒有將n開根號,看懂了上面的,這個應該也懂的差不多了
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <string> using namespace std; #define ll __int64 ll mod=1e9+7; int main() { ll n, m; scanf("%I64d%I64d", &n, &m); ll ans = n%mod*(m%mod)%mod; ll sum=0, j, mm; for(ll i=1; i<=min(n, m); i++) { j = min(n/(n/i), m); ll s1 = i+j, s2 = j-i+1; if(s1%2==0) s1 = (s1/2)%mod, s2%=mod; else s1%=mod, s2 = (s2/2)%mod; mm = s1*s2%mod*(n/i%mod)%mod; sum = (sum+mm)%mod; i = j; } ans = (ans-sum+mod)%mod; printf("%I64d\n", ans); return 0; }