2020.8.1牛客多校第七场H题——Dividing

Dividing(整除分块)

今天打了牛客多校的比赛,H题一开始在找规律,兴奋的发现了一些小规律然后暴力算一遍。
结果如下:打到今天第一次看到127s的,就离谱
然后想了想直接除以2的那些其实值都是一样的,想着直接缩短了一半的时间应该能过,然后还是T。
后来想着每个值一样的区间都用乘法去做说不定就可以了(事实证明这也许就是整除分块吧,可惜之前没有学过,然后在确定区间l,r上出了问题
裂开~~
赛后问学姐,学姐说是整除分块,恍然大悟,我们当时思想和整除分块基本差不多了可惜细节不行。然后翻看了大佬的博客终于懂了一点,打算写下来有助于记忆。

题目

链接:https://ac.nowcoder.com/acm/contest/5672/H
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒

空间限制:C/C++ 262144K,其他语言524288K

64bit IO Format: %lld

题目描述

The following rules define a kind of integer tuple - the Legend Tuple:
(1, k) is always a Legend Tuple, where k is an integer. if (n, k) is a Legend Tuple, (n + k, k) is also a Legend Tuple. if (n, k) is a Legend Tuple, (nk, k) is also a Legend Tuple.
We want to know the number of the Legend Tuples (n, k) where 1≤n≤N,1≤k≤K1 \le n \le N, 1 \le k \le K1≤n≤N,1≤k≤K.

In order to avoid calculations of huge integers, report the answer modulo 109+710^9+7109+7 instead.
输入描述:
The input contains two integers N and K, 1≤N,K≤10121 \le N, K \le 10^{12}1≤N,K≤1012.
输出描述:
Output the answer modulo 109+710^9+7109+7.

示例1
输入
3 3
输出
8

示例2
输入
3 9
输出
14
把问题转化成整除分块的过程暂时不是很想打了(懒),等等回寝室慢慢磨吧,现在就直接上代码吧。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD=1e9+7;
int main(){
    ll n,k;
    scanf("%lld%lld",&n,&k);
    ll ans=n;
    ll up=min(n,k);       //在k>n的时候 ,有(n,k)=(n,n)+k-n 
    for (ll l = 2, r=1; l <=up; l = r + 1) //l和r为区间的左右端点,这区间中的所有数的值相同 
    {
        r=min(n/(n/l),up);     //求区间的方法,l的更新在for循环一行中 
        ans += ((r-l+1)%MOD)*(((n/l)*2)%MOD)%MOD+(r-l+1-(n%r==0))%MOD;//r-l+1为区间长度 ,(n/l*2)为值的一部分,加上后面的r-l+1 为全部,n%r==0用来判断刚好为因数的情况 
        ans%=MOD;
    }
    if(n<k)ans+=k-n;      //在k>n的时候 ,有(n,k)=(n,n)+k-n ,所以在这里加上 
    ans%=MOD;
    printf("%lld\n",ans);
}

这板子妙在哪里呢,妙就妙在 用r=min(n/(n/l),up)来求区间的右端点,然后左端点的更新放在每次循环结束。
r=min(n/(n/l),up)这个式子的证明暂时没有很弄懂,但是至少学到了,这里贴个大佬链接来看看证明过程
https://www.cnblogs.com/ZJNU-huyh/p/13373770.html
再贴个整除分块的板子

for (int l = 1, r; l <= n; l = r + 1)
{
    r = n / (n / l);
    ans += (r - l + 1) * (n / l);
}

如此如此,这般这般,整除分块真是妙不可言。

2020.08.01
20:42

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值