闲人の题解 P7441
说实话,当我看到这道题时还有点懵。
但是你静下来就会发现其实是一道数学思维的题。
我们可以把题抽象一下:
- 有T组数据据。
- 每一组数据有两个等差数列,公差分别为x,y;
- 两个数列最大的一个数不大于K;
一些小问题
细心地同学已经发现,我好像并没有考虑-K的情况。
why?
很简单
so我们可以不用考虑-K的情况
进入正解
Round1
我们看看样例中的两个等差数列:
2 4 6 8 10
3 6 9
因为每一片叶子和每一片雪花只能用一遍
所以我们可以用其中一个数列中最小的数字去加另一个数列的最大数。
为什么这样做?
不难发现
这是一个递增的关系
有兴趣的小朋友可以证明一下为什么。
如果加起来不足K怎么办?
那我们就用一个数列的第一个去加另一个数列的倒数第二个数。
Round 2
新的问题又出现:应该用哪一个数列的第一个数去加另一个数列的最后一个数呢?
再看一下样例:
2 4 6 8 10
3 6 9
可以发现我们最好情况下可以配对所有数字最少数列中的所有数,所以我们应该尽量把数字少的数列中的数字用完。
Round 3
那么思路就出来了:
- 找出数列短的那一个。
- 用这个数列的第一个去加另一数列的最后一个数,如果大于等于K,则证明这个数列中的数都能匹配,直接输出此数列的数字个数。
- 如果2没有执行我们就用这个数列的第一个数去加另一个数列的倒数第二个数。
Round 4 之亿点点问题
看看第二个样例是什么
1
0 0 1
有“0”??????
没错,如果有“0”,就会比较麻烦。
- 如果两个公差都是“0”,那必然输出“0”,没说的
- 如果其中一个公差是“0”,我就还要判断另一个数列的最后一个数等不等于K,若是,就输出“1”。如不是,就只能输出“0”了
Round 5
最后还是附上代码(代码的思路有一点点不一样,它说用数列数字多的那一个数列的最后一个数依次加另一数列的1,2,3...个数)
#include<cstdio>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int find_ans(ll x,ll y,ll k){
ll X_ = k / x, X = x, Y_2 = k % y;
ll Y_ = k / y, Y_last = k - Y_2;
for(ll i = Y_ ; i >= 0; -- i){
if((Y_last + x) >= k){
cout << X_ << endl;
return 0;
}
else {
x += X;
X_ --;
}
}
cout << "0" << endl;
return 0;
}
int main(){
ll n;
cin >> n;
for(ll i = 1; i <= n; i ++){
ll a,b,c;
cin >> a >> b >> c;
if(a == 0 || b == 0){
if(a == 0 && b == 0){
cout << "0" << endl;
}
else if(a == 0 && c % b == 0){
cout << "1" << endl;
}
else if(b == 0 && c % a == 0){
cout << "1" << endl;
}
else cout << "0" << endl;
}
else{
if(a >= b){
find_ans(a,b,c);
}
else {find_ans(b,a,c);}
}
}
return 0;
}
后记
这篇题解中有些话可能有点绕,需要好好思考一下。
因为是我第一篇发的题解(前面(一年前)发过只有代码的题解没有过) 也许有不足之处,还请随时指出。
感谢阅览!
赏