2 条题解
-
1
这题最快应该是双指针(我在 L16 学过这题)。
笑四我根本不懂怎么二分一步一步来,先尝试暴力。
因为将数字变成原序列中没有的数只会浪费增加次数,因此我们可以先将原序列排序,然后枚举 ,计算能把多少个数变成 。因为只能由小变大,我们应该枚举 左边的数。而数字越小消耗的次数越多,所以我们应该从右往左枚举。如果将当前的数变成 消耗的次数小于剩余次数,就将 的个数加一并扣减剩余次数。具体看代码吧。
#include <iostream> #include <algorithm> using namespace std; int n,k,ans,num; long long a[100001],sum[100001]; int main() { cin>>n>>k; for (int i=1;i<=n;i++){ cin>>a[i]; } sort(a+1,a+n+1); for (int i=1;i<=n;i++){ int now=1,kkksc03=k; for (int j=i-1;j;j--){ if (kkksc03>=a[i]-a[j]){ kkksc03-=a[i]-a[j];//算出将a[j]变成a[i]消耗的次数 now++; }else{ break; } } if (now>ans){ ans=now; num=a[i]; } } cout<<ans<<" "<<num; return 0; }
吐槽数据,这么暴力的代码都能过 个点……接下来考虑优化。其实这个问题就是在原序列中找一个区间,使得区间里数的总和等于 ( 和 是左右端点,因为序列已经排好序所以可以直接用 。其实也就是把区间内的数都变成 ,此时区间内数的总和就是 ),求这个区间最长有多长以及最长区间对应的 。不难得出 是严格非降的:因为如果 增加一,消耗的次数不会比原来少, 不可能减少。于是就想到了
熟悉的双指针,细节详见代码。#include <bits/stdc++.h> using namespace std; int n,k,l=1,r=1,ans,num; long long a[100001],sum[100001]; int main(){ cin>>n>>k; for (int i=1;i<=n;i++){ cin>>a[i]; } sort(a+1,a+n+1); for (int i=1;i<=n;i++){ sum[i]=sum[i-1]+a[i]; } for (int l=1,r=1;r<=n;r++){ while (sum[r]-sum[l-1]+k<a[r]*(r-l+1)){//求出最小合法的l l++; } if (r-l+1>ans){ ans=r-l+1; num=a[r]; } } cout<<ans<<" "<<num; return 0; }
注意,虽然双指针是嵌套循环,但其时间复杂度是是 的,请大家自行思考。
-
-14
写题解请注意
不鼓励大家写题解,但注意题解格式。
题解一定不要有思路解析或代码注释,不让别人理解你的思路
也不是你的能力的检验,要只放无意义的代码给大家复制,那就是做题的初心。
给代码两端加上这个并不会舒服一些:
```cpp
你的代码
```
</span>
这个点在键盘的左上角tab上面那个键,注意切换输入法
#include<iostream> using namespace std; int main() { int n; cin>>n;//这是一个注释 return 0; }
[Copy](javascript:;)
请注意严禁抄袭题解,写题解要只放代码,不需加上你的思路或代码注释。
抄袭题解一经发现直接取消成绩。
题解被删除的可能
- 代码符合格式规范
- 有思路讲解或者没有注释,
- 有意义的题解
大家携手共同维护一个良好的编程环境,如果一经发现,多次作乱。可能会被管理员拉黑,请注意,一旦拉黑即失去登陆资格
- 1
信息
- ID
- 1252
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 5
- 标签
- 递交数
- 158
- 已通过
- 59
- 上传者