http://www.lydsy.com/JudgeOnline/problem.php?id=1257
タイトル
n、kと入力して\ [\ sum_ {i = 1} ^ nk \ bmod i \]を要求します
$ 1 \ leqslant n、k \ leqslant 10 ^ 9 $
解決策
これはneerc2005のトピックです
直接残業として直接カウントされる場合
$ k \ bmod i $は、
\ [k- \ left \ lfloor \ frac {k} {i} \ right \ rfloor \ times i \]
時計を再生すると、$ \ left \ lfloor \ frac {k} {i} \ right \ rfloor $が繰り返されることがあります
次に、構造が繰り返されるのはいつですか
使用する必要があります
\ [\ left \ lfloor \ frac {k} {i} \ right \ rfloor \ leqslant \ left(\ frac {k} {i} \ right)\]
その後
\ [\ left \ lfloor \ frac {k} {\ left \ lfloor \ frac {k} {\ left \ lfloor \ frac {k} {i} \ right \ rfloor} \ right \ rfloor} \ right \ rfloor \ leqslant \ left \ lfloor \ frac {k} {\ left \ lfloor \ frac {k} {\ left(\ frac {k} {i} \ right)} \ right \ rfloor} \ right \ rfloor = \ left \ lfloor \ frac {k} {\ left \ lfloor i \ right \ rfloor} \ right \ rfloor = \ left \ lfloor \ frac {k} {i} \ right \ rfloor \]
\ [\ left \ lfloor \ frac {k} {\ left \ lfloor \ frac {k} {\ left \ lfloor \ frac {k} {i} \ right \ rfloor} \ right \ rfloor} \ right \ rfloor \ geqslant \ left \ lfloor \ frac {k} {\ left(\ frac {k} {\ left \ lfloor \ frac {k} {i} \ right \ rfloor} \ right)} \ right \ rfloor = \ left \ lfloor \ left \ lfloor \ frac {k} {i} \ right \ rfloor \ right \ rfloor = \ left \ lfloor \ frac {k} {i} \ right \ rfloor \]
だから
\ [\ left \ lfloor \ frac {k} {\ left \ lfloor \ frac {k} {\ left \ lfloor \ frac {k} {i} \ right \ rfloor} \ right \ rfloor} \ right \ rfloor = \左\ lfloor \ frac {k} {i} \右\ rfloor \]
$ x <y $の場合、中間部分も等しいはずです。
\ [\ left \ lfloor x \ right \ rfloor \ leqslant \ left \ lfloor y \ right \ rfloor \]
これによりパーツを高速化できますが、どれだけ高速化できますか?
直接テーブル検証:
int main(){ ll i = 1; int cnt = 0; while(i <int(1e9)){ cnt ++; printf( "%10lld"、i); i = int(1e9)/ i; i = int(1e9)/ i; i ++; } printf( "\ n%d \ n"、cnt); }
最悪のケースは63244サイクルのみ
次に、直接合計することができます
\ [\ sum_ {i = 1} ^ nk \ bmod i = nk- \ sum_ {i = 1} ^ n \ left \ lfloor \ frac {k} {i} \ right \ rfloor \ times i \]
各セグメントが等しい場合、2番目の項は算術シーケンスであり、制限時間を超える場合があります。
時間の複雑さは証明されませんが、証明のために多くの時間を節約できます
ACコード
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #define REP(i、a、b)for(int i =(a); i <(b); i ++) #define REPE (i、a、b)for(int i =(a); i <=(b); i ++) #define PERE(i、a、b)for(int i =(a); i> =(b) ; i--) 名前空間stdを使用; typedef long long ll; int main(){ int n、k; scanf( "%d%d"、&n、&k); ll i = 1、ans =(ll)n * k; while(i <= n){ if(i> k){ break; } else { int j = k /(k / i); if(j> n)j = n; ans-=(i + j)*(k / i)*(j-i + 1)/ 2; i = j + 1; } } printf( "%lld \ n"、ans); }