P2261 [CQOI2007]余数求和(整除分块)

P2261 [CQOI2007]余数求和(整除分块)

思路:整除分块。

G ( n , k ) G(n,k) G(n,k)

= ∑ i = 1 n k   m o d   i =\sum\limits_{i=1}^n k\bmod i =i=1nkmodi

= ∑ i = 1 n k − ⌊ k i ⌋ × i =\sum\limits_{i=1}^n k-\lfloor\dfrac{k}{i}\rfloor\times i =i=1nkik×i

= n k − ∑ i = 1 n ⌊ k i ⌋ × i =nk-\sum\limits_{i=1}^n\lfloor\dfrac{k}{i}\rfloor\times i =nki=1nik×i

对于 x = ⌊ k i ⌋ x=\lfloor\dfrac{k}{i}\rfloor x=ik相同的 i i i,是一个区间 [ l , r ] [l,r] [l,r],因此我们可以进行分块运算。

对于当前区间左端点 l l l,它对于的 r = k ⌊ k l ⌋ r=\dfrac{k}{\lfloor\dfrac{k}{l}\rfloor} r=lkk

即: ∑ i = l r ⌊ k i ⌋ × i = x ∑ i = l r i = x ( l + r ) ( r − l + 1 ) 2 \sum\limits_{i=l}^r \lfloor\dfrac{k}{i}\rfloor\times i=x \sum\limits_{i=l}^r i=\dfrac{x(l+r)(r-l+1)}{2} i=lrik×i=xi=lri=2x(l+r)(rl+1)

然后 l = r + 1 l=r+1 l=r+1进入下一个块即可。

时间复杂度: O ( n ) O(\sqrt{n}) O(n )

因为此题: k k k可能小于 n n n所以我们直接取到 m i n ( n , k ) min(n,k) min(n,k)为止即可。

#include
using namespace std;
typedef long long ll;
const int N=1e3+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair
#define fi first
#define se second
#define pb push_back
int main(){
	ll n,k;
	scanf("%lld%lld",&n,&k);
	ll ans=n*k;
	for(ll l=1,r;l<=min(n,k);l=r+1){
		r=min(k/(k/l),n);
		ans-=k/l*(r-l+1)*(l+r)>>1;
	}
	printf("%lld\n",ans);
	return 0;
}

你可能感兴趣的:(数论,分块运算)