zoukankan      html  css  js  c++  java
  • 2020牛客暑期多校训练营(第七场)H.Dividing(数论:整除分块)(详细)

    地址:https://ac.nowcoder.com/acm/contest/5672/H?&headNav=acm

    题意:

    (1,k)是传奇元组

    如果(n,k)是,那么(n+k,k)是

    如果(n,k)是,那么(n*k,k)是

    解析:

    假设有传奇元组:(n*k,k)

    那么(n*k+k,k)也为传奇元组,那么(n*k+k)%k==1

    所以经过一系列尝试,发现满足传奇元组有两个条件:n%k==0||n%k==1

    即:n%k==0  ||  (n-1)%k==0

    可以想到,对n,k进行n*k的枚举,很显然,会T。

    那么可以尝试固定一个n,枚举k。

    可以发现,将n定为N,那么对于每一个k来讲,一列含有n/k个数满足n%k==0。

    所以,固定N,枚举k即可。有公式:

    (图来自https://www.cnblogs.com/charles1999/p/13424380.html)

    针对n,k极大的情况,用到了除法分块

    对于i<=k&&i<=n这里,需要说明一下,当n<k时,n/(n/i)这里出现了分母为0的情况,所以对于n<k,算到i==n即可。n>k,k算到底即可。

    #include<bits/stdc++.h>
    #include<iostream>
    #include<cstring>
    #include<string.h>
    #include<cmath>
    #include<vector>
    #include<map>
    using namespace std;
    typedef long long ll;
    const int mod=1e9+7;
    const int maxn=1e5+20;
    int a[maxn];
    ll n,k;
    ll ac(ll n)
    {
        ll sum=0;
        ll i=2,j;
        for(;i<=n&&i<=k;i=j+1)
        {
            j=min((n/(n/i)),k);  //范围限定
            sum+=((j-i+1)%mod*(n/i)%mod)%mod;  //[i,j]范围的n/i相等,所以为j-i+1个n%i==0
        }
        return sum;
    }
    int main()
    {
    
        cin>>n>>k;
        ll sum=(n+k-1)%mod;//最左边一列,最上面一行
        cout<<(sum+ac(n)+ac(n-1))%mod<<endl; 
    }
  • 相关阅读:
    第二章初识MySQL
    第一章 数据库
    Java&SQL7
    Java&SQL
    Java&SQL6
    Java&SQL5
    Java&SQL4
    Java&SQL3
    Java&SQL2
    博客地址已搬迁
  • 原文地址:https://www.cnblogs.com/liyexin/p/13430832.html
Copyright © 2011-2022 走看看