T1
题目描述:
求满足下列条件的二元组(a,b)的个数
a mod b = b div a
1<=a,b<=n
样例输入:
10
样例输出:
21
数据范围:
对于 10%的数据: (n) <= (10^3)
对于 20%的数据: (n) <= (10^5)
对于 30%的数据: (n) <= (10^7)
对于 40%的数据: (n) <= (10^{12})
当经过手模样例和一些自己出的样例之后,可以发现,(a)肯定不能等于(b),那么就分为两种情况讨论:
<1>:
(a<b)时,(a;mod;b=a),即(leftlfloordfrac{b}{a} ight floor=a) 。显然,(a)小于(sqrt{n}),直接等差数列(O(1))就出即可,需特判一下(sqrt{n})。
<2>:
(a>b)时,(leftlfloordfrac{b}{a}
ight
floor=0)。
即为
[sumlimits_{a,b} {a;mod;b=0}
]
考虑转换成枚举(b),即为
[sumlimits_{b} {(leftlfloordfrac{n}{b}
ight
floor-1)}
]
减一是为了除去(a=b)的情况。
转化之后即为
[sumlimits_{b} {leftlfloordfrac{n}{b}
ight
floor}-n
]
即为下底函数分块,可将取值相同的一块一起处理。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e7+7;
#define il inline
#define vocaloid(v) (v>='0'&&v<='9')
#define ll long long
template <typename T>
il void read(T &x)
{
x=0;char v=getchar();
while(!vocaloid(v)) v=getchar();
while(vocaloid(v)) {x=(x<<1)+(x<<3)+v-'0';v=getchar();}
}
template <typename T>
il void write(T x)
{
if(x>9) write(x/10);
putchar(x%10+'0');
}
bool flag=1;
ll n,ans,a[5000007],cnt;
int main()
{
freopen("diyiti.in","r",stdin);
freopen("diyiti.out","w",stdout);
read(n);
ll mid=sqrt(n);
for(int i=1;i<=mid;i++) a[++cnt]=i;
int now=cnt;
for(int i=now;i>=1;i--) a[++cnt]=n/a[i];
for(int i=1;i<=cnt;i++)
ans+=(a[i]-a[i-1])*(n/a[i]);
ans-=n;
ans+=(mid-1)*mid/2-1;
ans+=min(mid,n-mid*mid+1);
write(ans);putchar('
');
return 0;
}