链接: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); }