ldoj平台:竞赛3191 | 程序设计在线评测平台 (ldu.edu.cn)
A.Sum
给定 x ,y , 求的值 .
其中 ,代表向下取整
输入描述
第一行一个正整数 T(1≤T≤100), 表示测试用例的数目。每个测试用例占一行。
接下来的 T 行,每行两个正整数 。
输出描述
输出共 T 行,每个一个正整数,表示答案。
样例
输入:
9
3 4
2 100
4 3
50 3
12 4
69 420
12345 6789
123456 789
12345678 9输出:
2
1
3
6
8
148
53494
161259
45
思路:
很容易知道在大于0时间是单调递增的,所以在某点之前取
,在某点之后取x,这个点很容易求出来(循环跑或者公式都可以),前段计算时间就变成了
, 化简变成了
,因为下取整,所以后边的分数就没有了,前半段就变成了前n项和。
后半段可以通过分段计算,第一段的值就是(a就是刚才求出的分割点),根据这个值,可以求出值为
的区间的长度,从这个值开始,后面的值就是前一个值-1,这样循环求就能求出来
部分代码:
void solve(){
ll x,y;
ll sum = 0;
cin >> x >> y;
ll a = 0;
for(int i = 1;;i++){//求解分割点
if(x <= i * i + i + 1){
a = i - 1;
break;
}
}
if(y < a){//如果说泡不到分割点,就直接计算前半段输出
sum = y * (y + 1) / 2;
cout << sum << "\n";
return ;
}
sum = a * (a + 1) / 2;
a++;
ll l = a;
ll shang = x / (a + 1);
if(shang == 0){//很关键,判断以下是否为0,否则后边计算区间右端点时间就会挂
cout << sum << "\n";
return;
}
ll r = x / shang - 1;
while(1){
if(y <= r){//算到边界就可以,超多的算就加多了
sum += (y - l + 1) * shang;
break;
}
sum += (r - l + 1) * shang;
shang--;
if(shang == 0)break;//如果这个值为0了,后面就没必要计算了,后面的贡献
l = r + 1;
r = x / shang - 1;
}
cout << sum << "\n";
}