2020牛客暑期多校训练营(第七场)H.Dividing

2020牛客暑期多校训练营(第七场)H.Dividing

题目链接

题目描述

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 1 \le n \le N, 1 \le k \le K 1nN,1kK.

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

输入描述:

The input contains two integers N and K, 1 ≤ N , K ≤ 1 0 12 1 \le N, K \le 10^{12} 1N,K1012.

输出描述:

Output the answer modulo 1 0 9 + 7 10^9+7 109+7.

示例1

输入

3 3

输出

8

示例2

输入

3 9

输出

14

这题题意简单明确,但实际上有点坑,先打个表(行为 n n n,列为 k k k)

1,1 1,2 1,3 1,4 ⋯ \cdots
2,1 2,2 2,3 2,4 ⋯ \cdots
3,1 3,2 3,3 3,4 ⋯ \cdots
4,1 4,2 4,3 4,4 ⋯ \cdots
5,1 5,2 5,3 5,4 ⋯ \cdots

我标红的是不能选的,首先假如所有组合都满足条件,答案肯定就是 n ∗ k n*k nk,但实际上肯定少一点,那我们就考虑每一列的值:
我们从第二列开始考虑,因为第一列情况比较特殊~

  • 第二列:横坐标为 2 ∗ x 2*x 2x 或者 2 ∗ x − 1 2*x-1 2x1 时,满足条件, x ∈ N x\in N xN
  • 第三列:横坐标为 3 ∗ x 3*x 3x 或者 3 ∗ x − 2 3*x-2 3x2 时,满足条件, x ∈ N x\in N xN
  • 第四列:横坐标为 4 ∗ x 4*x 4x 或者 4 ∗ x − 3 4*x-3 4x3 时,满足条件, x ∈ N x\in N xN
    ⋯ \cdots
  • k k k 列:横坐标为 k ∗ x k*x kx 或者 k ∗ x − ( k − 1 ) k*x-(k-1) kx(k1) 时,满足条件, x ∈ N x\in N xN

那么每一列满足条件的都可以算出来,对第 i i i 列答案为 ⌊ ( n + i − 1 ) i ⌋ + ⌊ n i ⌋ \lfloor\frac{(n+i-1)}{i}\rfloor+\lfloor\frac{n}{i}\rfloor i(n+i1)+in,注意千万别合并,因为是向下取整,比赛时因为这个纠结了很久/(ㄒoㄒ)/~~,那么答案就是 ∑ i = 1 n ( ⌊ ( n + i − 1 ) i ⌋ + ⌊ n i ⌋ ) \sum_{i=1}^n(\lfloor\frac{(n+i-1)}{i}\rfloor+\lfloor\frac{n}{i}\rfloor) i=1n(i(n+i1)+in),因为数据 n n n 比较大,直接算肯定是 T T T 飞的,所以我们得用数论的知识——刷过 k u a n g b i n kuangbin kuangbin 基础数论的对这个 ⌊ n i ⌋ \lfloor\frac{n}{i}\rfloor in 肯定很敏感,没错,题目名称也给了一点提升,就是除法分块,我们将答案拆分一下 ∑ i = 1 n ( ⌊ ( n + i − 1 ) i ⌋ + ⌊ n i ⌋ ) = ∑ i = 1 n ( ⌊ ( n − 1 ) i ⌋ + ⌊ n i ⌋ ) + k \sum_{i=1}^n(\lfloor\frac{(n+i-1)}{i}\rfloor+\lfloor\frac{n}{i}\rfloor)=\sum_{i=1}^n(\lfloor\frac{(n-1)}{i}\rfloor+\lfloor\frac{n}{i}\rfloor)+k i=1n(i(n+i1)+in)=i=1n(i(n1)+in)+k,用除法分块就可以在 O ( n ) O(\sqrt n) O(n ) 的时间里算出前面那个答案,那么这题到这里就解决了吗?别忘了,还有第一列,我们用上面推导的公式算第一列的时候,会发现多算了一个 n n n,所以最后答案还要减去一个 n n n。整体思路就是这样,AC代码如下:


#include
typedef long long ll;
using namespace std;
const ll mod=1e9+7;
inline ll solve(ll n,ll k)//除法分块
{
    ll ans=0,j;
	for (register ll i=1;i<=k;i=j+1){
        j=n/(n/i);
        ans+=(min(j,k)-i+1)*(n/i);
    }
    return ans;
}

int main()
{
	ll n,k;
    scanf("%lld%lld", &n,&k);
    ll ans=(solve(n,min(n,k))%mod+solve(n-1,min(n-1,k))%mod+k%mod)%mod-n;
    if(ans<0) ans=mod-abs(ans)%mod;//负数取模
    printf("%lld\n",ans);
	return 0;
}

你可能感兴趣的:(思维,数论,牛客)