AcWing 199. 余数之和

原题链接

考察:推导公式

蓝书是将本题归纳到约数里,我实在没看出来这道题和约数有啥关系

这道题计算k%(1~n)的值,实际上是求k - [k/i]*i的值.转化后将式子累加得到n*k-累加和[k/i]*i.

n*k是已知的式子,i在循环里枚举,唯一要求的是[k/i].一个个求是肯定不行的,因此需要求得某些规律

假设n==10,k==10时,可以发现:

k/i 10 5 3 2 2 1 1 1 1 1
i 1 2 3 4 5 6 7 8 9 10

当i>10,k/i就==0,因此不再画出

在i=4~5和6~9的时候,我们可以发现k/i是连续的.我们可以将这段通过求和公式累加而避免循环.通过推导发现连续区间的下界在k/[k/i].上界就是下界+1.

然后就可以通过求和公式计算答案

易错:

  1. 当我们计算连续区间的和时,要将tmp放在前面,这样式子就被转化为long long防止溢出
  2. 计算下界的时候要防止下界超出n范围外
  3. 总共有2sqrt(n)个不同的取值,分为分母<=sqrt(a)与>sqrt(a)证明.
 1 #include <iostream>
 2 #include <cstring>
 3 using namespace std;
 4 typedef long long ll;
 5 ll n,k,ans;
 6 int main()
 7 {
 8     ll st,ed;
 9     scanf("%lld%lld",&n,&k);
10     ans = n*k;
11     for(ll i=1;i<=n;i=ed+1)
12     {
13         int t = k/i;
14         st = k/(t+1)+1,ed = t==0?n:min(k/t,n);
15         ll sum = (st+ed)*(ed-st+1)/2*t;
16         ans-=sum;
17     }
18     printf("%lld\n",ans);
19     return 0;
20 }

 

2021.1.24 打表感觉更容易发现规律,通过打表发现k/i有连续区间.然后二刷还是踩了几个坑

  1. 关于ed的取值,ed一定不能超过n,当k>n,k/i==1时,k/t就会超过n
  2. 不记得会不会爆int,干脆全用了long long

        

posted @ 2021-01-16 17:50  acmloser  阅读(75)  评论(0编辑  收藏  举报