地址: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即可。有公式:
(图来自https://www.cnblogs.com/charles1999/p/13424380.html)
针对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; }