zoukankan      html  css  js  c++  java
  • 整除分块 学习笔记

    整除分块

    HGOI20181027模拟题:

    给定n,m,快速求出 FHT(n,m) % (1e9+7)的值。

     对于100%的数据: n,m <= 1,000,000,000

    然后为了这个问题我们去找了整除分块的算法:

    (例题) [CQOI2007]余数求和

            

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

     解析:

    对于G(n,k) 化简 显然 a%b=a-[a/b]*b

     

    在C++中floor(a/b)=a/b 所以我们打个表来看看k/i的规律

    # include<bits/stdc++.h>
    using namespace std;
    int main()
    {
        int n=10;
        printf("i      ");
        for (int i=1;i<=n;i++)
           printf("%d ",i);
        putchar('
    '); printf("%d/i  ",n); 
        for (int i=1;i<=n;i++) 
         printf("%d ",n/i);
        putchar('
    ');
        return 0;
    } 

    我们发现这样的规律:n/i的值相同的总是出现在相邻位置!

     

    在上面的式子中也就是说k/i这个东西是下取整的在一个区间内是不会变的

    设[k/i]=a (这里是下取整[]): a<=k/i<a+1

    然后参变分离:

    得 :      i<=k/a;     i>k/(a+1)

    所以在这里我们发现了对于区间i∈[L,R]其[k/i]是一个定值,当且仅当L=k/([k/i]+1)+1 ; R=k/[k/i],

    所以这里的区间[l,r]可以写成: [k/(k/i+1)+1,k/(k/i) ] (这里的/是整除,和C++中/等价)

    对于这里区间他们的floor(k/i)是一定的,唯一的是i在+1 +2 +3的递增所以是一个d=1的等差数列(起始值是k/i),我们只要知道左右区间就可以知道求和以后的值了

    • code:(100pts)
    # include <bits/stdc++.h>
    # define int long long
    using namespace std;
    int n,k;
    int calc(int n,int k) {
        int ret=0;
        for (int l=1,r;l<=n;l=r+1) {
            if (k/l!=0) r=min(k/(k/l),n);
            else r=n;
            ret+=(k/l)*(r-l+1)*(l+r)/2;
        }
        return ret;
    }
    int G(int n,int k) { return n*k-calc(n,k);}
    signed main()
    {
        scanf("%lld%lld",&n,&k);
        printf("%lld
    ",G(n,k));
        return 0;
    }

    HGOI20181027模拟题:

    给定n,m,快速求出 FHT(n,m)% (1e9+7)的值。

     对于100%的数据: n,m <= 1,000,000,000

    先对式子化简:

    然后就是求一部分就行了,然后就是和上面处理方法一样令G(n,k)中n=k就可以解决了

    # include <bits/stdc++.h>
    # define int long long
    using namespace std;
    const int mo=1e9+7;
    int calc(int n) {
        int ret=0;
        for (int l=1,r;l<=n;l=r+1) {
            if (n/l!=0) r=min(n/(n/l),n);
            else r=n;
            ret=(ret+(n/l)*(r-l+1)*(l+r)/2%mo)%mo;
        }
        return (n*n%mo-ret%mo+mo)%mo;
    }
    int FHT(int n,int m){ return calc(n)*calc(m)%mo;}
    signed main()
    {
        int n,m; scanf("%lld%lld",&n,&m);
        printf("%lld
    ",FHT(n,m));
        return 0;
    }
  • 相关阅读:
    疫情控制
    数据结构1
    NOIP 模拟 921
    ml-agents项目实践(一)
    Appium的安装及简单的使用介绍
    移动设备管理平台的搭建(基于STF/ATXServer2)
    ClickHouse利器—如何提高留存计算速度
    Linux基本操作命令
    深度学习与强化学习的两大联姻:DQN与DDPG的对比分析
    漏洞扫描软件AWVS的介绍和使用
  • 原文地址:https://www.cnblogs.com/ljc20020730/p/9862068.html
Copyright © 2011-2022 走看看