洛谷 P2261 [CQOI2007]余数求和
一看就知道是一个数学题。嘿嘿~
讲讲各种分的做法吧。
30分做法:不知道,这大概是这题的难点吧!
60分做法:
一是直接暴力,看下代码吧~
#include <bits/stdc++.h>
using namespace std;
typedef int _int;
#define int long long
_int main()
{
int n,k,ans=0;
cin>>n>>k;
for (int i=1;i<=n;++i) {
ans+=(k%i);
}
cout<<ans;
return 0;
}
第二种做法非常接近正解。
首先显然\(k~mod~i=k-\lfloor \frac{k}{i} \rfloor*i\)。
所以我们马上一波转化,\(\sum_{i=1}^{n}k~mod~i=n*k-\sum_{i=1}^{n}\lfloor \frac{k}{i} \rfloor*i\)。
那么这一截\(\sum_{i=1}^{n}\lfloor \frac{k}{i} \rfloor*i\)怎么求呢?
这个时候,直觉会告诉我们,\(\lfloor \frac{k}{i} \rfloor*i\)很有问题。
因为是向下取整,所以会有许多\(\lfloor \frac{k}{i} \rfloor\)是一样的。于是就会有一个一个的区间。
对于每个这样的区间,在乘一个\(i\)后,显然是一个等差数列。
不信看这个:
\((int)8/3=(int)8/4=2~~~~=>~~~~8/3*3+2=8/4*4\)
所以我们可以枚举\(i\),对于每一个\(i\),求出\(t=k/i\),
令\(l=i,r=min(n,k)\)二分,如果\(mid/i=t,l\)扩大,否则\(r\)缩小。
找到后直接等差数列求和。
最后使\(i=r+1\)。这样表面时间复杂度是\(O(\sqrt{n}*log(n))\)。
实则不然,因为我们的\(i\)跳跃的距离基本上很小很小,所以这代码比\(O(n)\)还慢!
看下代码吧!
#include <bits/stdc++.h>
using namespace std;
typedef int _int;
#define int long long
int n,k,ans;
_int main()
{
cin>>n>>k;
ans=n*k;
for (int i=1;i<=min(n,k);++i) {
int l=i,r=min(n,k),t=k/i,j=i;
while (l<=r) {
int mid=(l+r)/2;
if (mid/i==t) l=mid+1,j=mid;
else r=mid-1;
}
int a1=t*i,an=a1+(j-i)*t,g=j-i+1;
ans-=(g*(a1+an)/2);
i=j;
}
cout<<ans;
return 0;
}
100正解:
有了上面第二个60分做法的思路,正解就不言而喻了。
只要把\(log(n)\)找区间改成\(O(1)\)就好了。
具体怎么改呢?
我们同样的枚举\(i\),假设区间为\([l,r]\),那么\(l=i\)显然,然后就剩\(r\)有点难搞了。
想想,我们每一段的公差都是\(\lfloor \frac{k}{i} \rfloor\),那么显然当\(k~mod~i=0\)时,\(r\)截止。
所以,\(r=k/(k/l)\)。
那么,就完结了,上代码!真正的极简AC难懂~
#include <bits/stdc++.h>
using namespace std;
typedef int _int;
#define int long long
int n,k,ans;
_int main()
{
cin>>n>>k;
ans=n*k;
for (int i=1;i<n;++i) {
int l=i,t=k/l,r=t?min(n,k/t):n;
int a1=t*l,an=a1+(r-l)*t,g=r-l+1;
ans-=(g*(a1+an)/2);
i=r;
}
cout<<ans;
return 0;
}
最新文章
- Hadoop日常维护系列——Hadoop添加删除节点
- PHP_Cli模式初涉——转载一篇
- 漫谈Linux内核哈希表(1)
- MySQL创建一个具有root权限的用户
- CocoSocket开源下载与编写经验分享
- [51单片机] nRF24L01 无线模块 测试 按键-灯-远程控制
- 【Bootstrap基础学习】02 Bootstrap的布局组件应用示例
- Linux大文件分割split和合并cat使用方法
- SQL批量修改表名
- leetcode@ [208] Implement Trie (Prefix Tree)
- SQL Server数据库---》增删查改
- 华为OJ之最长公共子串
- 如何在本地同时管理github仓库和codingnet仓库?
- Cocos 2d TestCPP 学习
- 第 7 章 多主机管理 - 047 - 管理 Machine
- AC自动机(病毒侵袭 )
- Python的容器、生成器、迭代器、可迭代对象的家谱
- Spark2 Dataset多维度统计cube与rollup
- 《C语言程序设计》指针篇<;二>;
- (连通图 模板题)迷宫城堡--hdu--1269
热门文章
- Python 的条件语句和循环语句
- redis 使用内存超过maxmemory
- NIO之阻塞IO与非阻塞IO(包含Selector使用)
- NIO之Channel聚集(gather)写入与分散(scatter)读取
- nginx源码学习_数据结构(ngx_str_t)
- mysql命令:set sql_log_bin=on/off
- oracle中查看sql语句的执行计划
- TCP/IP笔记(一)网络基础知识
- hdu 4272 LianLianKan 状态压缩
- 简单介绍一下vue2.0