Luogu P2261 [CQOI2007]余数求和|数论|余数

余数求和

题目描述

Problem

思路

暴力求解(暴力大法好)
优化思路:
余数之和:
n,k;
[求和]k%i(i:1 to n);
优化:
优化1、i大于k时,k%i=k;
优化2、k%i=k-k/ii
[求和](k%i)=[求和](k-k/i*i)
观察得到:
i,k除以区间[i,k/(k/i)]内任意数的结果是一样的
对于这样的区间,[求和]k/i
i可以提取公因式k/i
剩下的i累加,用等差数列求和得到结果。

Code

#include <cstdio>
#include <iostream>
#define ll long long
using namespace std;
ll n,k,ans;
int main(){
	scanf("%lld%lld",&n,&k);
	//优化2中k-k/i*i=>优化1+(n-k)*k-k/i*i; 
	ans=n*k;//优化1
	//优化2 (分块)
	ll i=1,j;
	while(i<=n){
		if(k>i) j=min(k/(k/i),n);//注意越界 
		else j=n;
		//提取公因式(k/l)
		//等差数列求和 
		ans-=(k/i)*((j-i+1)*(i+j)/2); 
		i=j+1;
	} 
	printf("%lld",ans);
	return 0;
}

原文地址:https://www.cnblogs.com/saitoasuka/p/10169204.html