BZOJ 1257残りの合計

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); 
}

 

おすすめ

転載: www.cnblogs.com/sahdsg/p/12708261.html