地址: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即可。有公式:
针对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;
}