P2261 remainder sum

Questions surface: https: //www.luogu.org/problemnew/show/P2261

First, let's deal with what n> = k case, because a good deal with this situation:

G (n, k) = k% 1 + k% 2 + ...... + k% n, then when n> = k, n> = k k% i portions is k, then n is <k a

Here, we define [c] as c rounding to the next.

We find that the [k / 2] +1 to k in this range, k% i is an arithmetic sequence with a tolerance of 1

In [k / 3] +1 to [k / 2] in this range, k% i is an arithmetic sequence, a tolerance of 2

In [k / 4] +1 to [k / 3] in this range, k% i is an arithmetic sequence, a tolerance of 3

.........

Up to [k / √k] +1 to [k / (√k-1)] in the interval, k% i is an arithmetic sequence, tolerance (√k-1).

The remaining 1 to [k / √k] section can be solved by direct violence.

In this way, we can use O (√k) to solve.

And then discuss the more difficult to think of n <k of the situation,

When n <k, the portion does not exist naturally k% i can be calculated directly, and

Some people may ask, this is not the simpler it? Do not direct the excess part, then given above is calculated not on the list,

Yes, most of this, but we need to consider that there may range given above, n is not included, that is not necessary to count interval does not include those of the n.

So, we need to find a range, which includes the n, and the rest are done by the above method can be.

Code:

#include<iostream>
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<ctime> using namespace std;
long long n,i,k,l,ans;//注意:整型默认为下取整 int main(){ cin>>n>>k; if(n>=k){//n>=k的部分 ans=(n-k)*1ll*k;//k%i的结果都是k,共有(n-k)个 } else{//否则n<k for(i=1;i*i<=k&&i<n;i++){//找一个区间使得n在其中,i就是区间上界的分母(详情看解释) if(k/i<n){//找到了 l=k/i;//记下来 break;//退出 } l=i;//否则就是当前的i } l++;//这里l++是为了把分母移到区间的下界(详情看解释) ans=1ll*(n-l+1)*(k%n+k/l*(n-l)+k%n)/2;//注意:这里是特殊处理含n的区间(其中上界是n,下界是l,公差为k/l) //高斯速算公式:(首项+末项)*项数/2 //(n-l+1)相当于项数,也就是区间长度 //k%n是首项 //k/l*(n-l)+k%n是末项,因为公差是k/l,中间有(n-l)个数,首项是k%n } for(i=k/n+1;i*i<=k;i++){//两种情况的交集,也就是都需要枚举,一开始i=k/n+1,i<=√k, //这里我们需要一个证明:为什么一开始i=k/n+1,当n>=k时,k/n+1刚好是1,也就是解释里第一个区间的上界分母 //当n<k时,因为刚刚已经处理过了包含n的区间,所以不必再处理,k/n+1刚好是包含n区间的下一个区间的上界分母 ans+=1ll*(k%i+i*(k/i-k/(i+1)-1)+k%i)*(k/i-k/(i+1))/2; //高斯速算公式:(首项+末项)*项数/2 //这里首项是k%i //末项是i*(k/i-k/(i+1)-1)+k%i,因为公差是i,其中一共有k/i-k/(i+1)-1个数,也就是项数-1(详情看解释) //项数是k/i-k/(i+1) } n=k/i;//1到[k/√k]的区间暴力求解 for(i=1;i<=n;i++){ ans+=k%i;//每次ans+k%i } cout<<ans<<endl; return 0; }

Guess you like

Origin www.cnblogs.com/ukcxrtjr/p/11163287.html