洛谷P2261 [CQOI2007]餘數求和(整除分塊)+一點學習筆記
阿新 • • 發佈:2018-12-30
題目背景
數學題,無背景
題目描述
給出正整數n和k,計算G(n, k)=k mod 1 + k mod 2 + k mod 3 + … + k mod n的值,其中k mod i表示k除以i的餘數。例如G(10, 5)=5 mod 1 + 5 mod 2 + 5 mod 3 + 5 mod 4 + 5 mod 5 …… + 5 mod 10=0+1+2+1+0+5+5+5+5+5=29
輸入輸出格式
輸入格式:
兩個整數n k
輸出格式:
答案
輸入輸出樣例
輸入樣例#1: 複製
10 5
輸出樣例#1: 複製
29
說明
30%: n,k <= 1000
60%: n,k <= 10^6
100% n,k <= 10^9
題解:題意很簡單,對於1e9範圍內的餘數求和,線性複雜度肯定是不夠的,這個時候就需要一個很神奇的思想,整除分塊:~~
首先考慮對於(n/i)從1-n求和,因為n/i很多的區間是相同的 從l-r中n/l==n/r,這些地方便可以直接跳過去大大的減小複雜度,
程式碼大概是這樣的:
for(int l=1,r;l<=n;l=r+1) { r=n/(n/l); ans+=(r-l+1)*(n/l); }
這樣就可以只有sqrt(n)的複雜度了~~
那麼我們回到這道題,對於這道題來說k%i=k-(k/i)*i; 那麼便可以發現在一個區間l-r中,k/i是相同的,那麼便可以直接求i的一個等差數列的和即可~~
#include<bits/stdc++.h> #define rep(i,s,t) for(int i=s;i<=t;i++) #define SI(i) scanf("%lld",&i) #define PI(i) printf("%lld\n",i) using namespace std; typedef long long ll; const int mod=1e9+7; const int MAX=1e5+5; const int INF=0x3f3f3f3f; const double eps=1e-8; int dir[9][2]={0,1,0,-1,1,0,-1,0, -1,-1,-1,1,1,-1,1,1}; template<class T>bool gmax(T &a,T b){return a<b?a=b,1:0;} template<class T>bool gmin(T &a,T b){return a>b?a=b,1:0;} template<class T>void gmod(T &a,T b){a=((a+b)%mod+mod)%mod;} typedef pair<ll,ll> PII; int main() { ll n,k; SI(n);SI(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)*(l+r)*(r-l+1)/2; } printf("%lld\n",ans); return 0; }