P2261 [CQOI2007]余数求和(整除分块)
思路:整除分块。
G(n,k)
=i=1∑nkmodi
=i=1∑nk−⌊ik⌋×i
=nk−i=1∑n⌊ik⌋×i
对于
x=⌊ik⌋相同的
i,是一个区间
[l,r],因此我们可以进行分块运算。
对于当前区间左端点
l,它对于的
r=⌊lk⌋k
即:
i=l∑r⌊ik⌋×i=xi=l∑ri=2x(l+r)(r−l+1)
然后
l=r+1进入下一个块即可。
时间复杂度:
O(n
)
因为此题:
k可能小于
n所以我们直接取到
min(n,k)为止即可。
#include<bits/stdc++.h>
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<int,int>
#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;
}