代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
int main(){
int t;
scanf("%d",&t);
while(t--){
ll n,k;
scanf("%lld%lld",&n,&k);
ll ans = n * (n + 1) / 2;
while(k-- && n){
n >>= 1;
ans -= n * (n + 1) / 2;
}
printf("%lld\n",ans);
}
return 0;
}
思路
本题要求计算各分数化简后的分子的总和。
按照朴素的计算方式,我们可以对逐个分数做化简,然后在逐个相加。
但本题的数据范围比较大(
1
≤
n
,
k
≤
1
0
9
1 \leq n,k \leq 10^9
1≤n,k≤109),使用这种方式必然超时。
这是需要打开思路,每一次不是固定地对单个分数进行化简,而是要对一批分数进行化简操作。
假定
n
=
5
,
k
=
2
n = 5,k = 2
n=5,k=2我们可以把处理过程表示如下。
即每一轮中将所有整除以2的分子约去2——减去约分前后的差值
n
′
∗
(
n
′
+
1
)
2
n' * (n' + 1) \over 2
2n′∗(n′+1)(其中
n
′
n'
n′等于每一轮开始前集合中最大的可约分分子值)。
在集合中没有可约的分子值时,化简结束,得到的ans值即为所求。
错误原因
定向思维,没有考虑到可以同时对集合中多个元素进行化简计算的方式。
这种处理方式,是将原本的逐个纵向串行计算换为横向的并行计算。
在遇到这类问题的时候,我们应该尽最大可能开拓解题的方式策略,进而再对逐个解题思路的可行性进行进一步的分析,而不应该主观上否定某个方式策略的可行性,思维闭锁,导致错过找到最优策略的机会。。
题目链接
原创不易,感谢支持!