1. 程式人生 > 實用技巧 >2020牛客多校第七場H題Dividing(整除分塊)

2020牛客多校第七場H題Dividing(整除分塊)

連結:https://ac.nowcoder.com/acm/contest/5672/H

題目描述

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≤K

In order to avoid calculations of huge integers, report the answer modulo 10^9+7 instead.

題意:定義了一種元組為可行,給你N,K,計算小於NK的可行組有多少個 對1e9+7取模

題解:根據題目描述我們可以瞭解到(1,k)始終是可行組,然後(1+k,k)(1+2k,k)...是可行組 (k,k)(2k,k)...也是可行組,我們可以理解題意寫出前面幾種可行組

我們可以發現n%k==1 是可行組 (n%k==0) 也是可行組,因此我們只要計算n/k有多少個 和(n-1)/k 也有多少就可以計算出答案,當然這些要滿足大條件 n<N,k<K。


(1,1)(1,2)(1,3)(1,4)(1,5)(1,6)(1,7)(1,8)(1,9)...

(2,1)(2,2)(3,3)(4,4)(5,5)(6,6)

(3,1)(3,2)(4,3)(5,4)

(4,1)(4,2)

(5,1)(5,2)

(6,1)


至此我們可以發現我們只要從1開始列舉(k) 算出n/k有多少種,再判斷n%k的結果是不是0,我們就可以計算出ans,但是題目k的範圍為1e12,時間複雜度為O(k)顯然不行。

這就需要整除分塊,什麼是整除分塊,就是用來計算 (n/i)能整除的有多少個,時間複雜度為O(sqrt(n))

ll diving( ll n){
    ll ans=0;
    for(ll l=3,r;l<=n;l=r+1){
        r=n/(n/l);
        ans+= ( ((r-l+1)%mod) * ((n/l)%mod) ) %mod;
        ans%=mod;
        cout<<l<<" "<<r<<" "<<ans<<endl;
    }
    return ans%mod;
    
}
View Code

此題還有一個坑點 N可以>K,所以我們直接套用上面的程式碼是不行的,會出現大於k的不符合的整除也被計算進來了,

因為我想法 是先把第一行跟左邊兩行加上,從i=3 開始整除,所以前面需要特判k==1。

#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1e3+7;
const ll mod =1e9+7;
typedef pair<int,int> pii;
typedef pair<double,double> pdd;

ll diving( ll n,ll k){
    ll ans=0;
    for(ll l=3,r;l<=n&&l<=k;l=r+1){
        r=min( n/(n/l),k);
        ans+= ( ((r-l+1)%mod) * ((n/l)%mod) ) %mod;
        ans%=mod;
    //    cout<<l<<" "<<r<<" "<<ans<<endl;
    }
    return ans%mod;
    
}

int main(){
    IOS
    ll n,k;
    cin>>n>>k;
    ll ans=0;
    if(k==1){
        ans=n%mod;
    }else 
        ans+=(k%mod+2*n%mod-2)%mod;
    //cout<<ans<<endl;
    ans+=diving(n,k)%mod+diving(n-1,k)%mod;
    cout<<ans%mod;
    
    return 0;
}