链接:https://ac.nowcoder.com/acm/contest/5672/H
题意:正整数二元组Legend Tuple(n,k)是这样定义的
(1,k)总是Legend Tuple
若(n,k)是Legend Tuple,那么(n+k,k)也是
若(n,k)是Legend Tuple, 那么(nk, k)也是
统计有多少个Legend Tuple(n,k)满足1<=n<=N, 1<=k<=K, 其中N,K是不超过1e12的整数
思路:
看也看不出来什么,这种题就是写写找找规律。
图片说明
能看出只有ak和ak+1满足题意(a是任意整数),当k=1的时候会有重复以外,ak和ak+1都不会重复,因此累加从2开始,别忘了1是a等于0的时候ak+1的值,因此计算ak+1的个数时应当是(n-1)/k + 1。
那么就可以写出公式:
图片说明
由于k很大,需要使用整数分块,复杂度O(√n)
之前我整除分块都没怎么细研究过直接套模板的,这次顺便复习了一下整除分块。
这次要解决的是
图片说明
这种形式。与普通的整除分块相比多考虑一下。
整除分块部分代码:
提醒一下就是这里的n经过取最小后可能已经改变了,使用的时候最好设一个nn来代替n

ans=0;
n=min(n,k); //公式中n/l可能为0(k>n的情况,不特判会出现k/0)
for(long long l=1,r;l<=n;l=r+1){
    r=min(k,n/(n/l));   //注意这里n/(n/l)可能会超过k,需要取min
    ans+=(r-l+1)*(n/l);
}

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
ll n, k, ans;
int main()
{
      scanf("%lld%lld",&n, &k);
      ans=(k-n) % mod;    
      ll nn = n, kk = k;

    k=min(k,n-1);                        
    for(long long l=1,r;l<=k;l=r+1){
        r=min(k,(n-1)/((n-1)/l));    
        ans= (ans + ((((n-1)/l)%mod)*((r-l+1)%mod))%mod) % mod ;
    }

    kk=min(kk,nn);                        
    for(long long l=1,r;l<=kk;l=r+1){
        r=min(kk,(nn)/((nn)/l));    
        ans= (ans + ((((nn)/l) % mod)*((r-l+1)%mod)) % mod) % mod;
    }

      printf("%lld\n",ans % mod);
}