数论——余数求和

数论——余数求和

题目

luogu:P2261 [CQOI2007]余数求和

算法分析

有的小伙伴看到这道题,第一感觉是这样的:好简单。这么水一道题,不是有手就行? 于是码出了这样一段代码:

int n,k,ans;
int main()
{
 n=readint(); k=readint();
 for(rg int i=1;i<=n;++i)
 {
  ans+=(k%i);
 }
 printf("%d\n",ans);
 return 0;
}

但是很抱歉的是,只能过一个点。

本题其实用到了整除分块的一些推论以及等差数列的相关知识。

  1. 对于 i i i属于 [ x , k / ( k / x ) ] [x,k/(k/x)] [x,k/(k/x)] k / i k/i k/i的值都相等。 例如 k = 15 , x = 9 k=15,x=9 k=15,x=9则对于 i i i属于区间 [ 9 , 15 / ( 15 / 9 ) ] [9,15/(15/9)] [9,15/(15/9)] [ 9 , 15 ] [9,15] [9,15] k / i k/i k/i的值都相等。
  2. 等差数列求和公式:(首项+末项)* 项数 /2。

在本题中 由于我们知道 k   m o d   i = k − k / i ∗ i k\,mod\,i=k-k/i*i kmodi=kk/ii,因此结果为 k ∗ n − ∑ i = 1 n k / i ∗ i k*n-\sum_{i=1}^{n}k/i*i kni=1nk/ii
具体代码如下:

Code

#include<iostream>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define rg register
#define ll long long 
using namespace std;
inline int sread()
{
 int x=0,f=1;char c=getchar();
 while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
 while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
 return f*x; 
}
long long int n,k,ans,ans1;
int main()
{
 scanf("%lld %lld",&n,&k);
 ans=n*k; 
 int l,r;
 for(rg int i=1;i<=n;i)
 {
 
  if(k>=i)
  {
   l=i;
   r=k/(k/i);
   if(r<=n) ans1+=(k/l*l+k/r*r)*(r-l+1)/2;
   else if(r>n) ans1+=(k/l*l+k/n*n)*(n-l+1)/2;
   i=r+1;
  }
  else if(k<i)
  {
   i++;
  }
 }
 ans=ans-ans1;
 printf("%lld\n",ans);
 return 0;
}

反思与总结

1.记得该开 l o n g   l o n g long\,long longlong的时候一定要开(我在这卡了半天)。
2.要对数学的基础知识熟练掌握并能灵活运用。
3.数论相关题目需要在思考的同时大量演算。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值