余数求和
题目描述
思路
暴力求解(暴力大法好)
优化思路:
余数之和:
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/ii可以提取公因式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;
}