作为小菜鸡的土豆片一直都是连800分的题都不一定写的出来,但是!这次土豆片竟然自己a了一道1200分的题(虽然可能是因为还是水题)!值得纪念!链接
题目:
样例:
土豆片的ac之路:
开始动脑思考:
要找最小操作数,也就是删除的最小个数,要删除尽量少的元素使数组元素总和达到s(目标总和)。
那么该如何实现捏?
土豆片的传统艺能——暴力!遍历出数组子集和等于s并且使子集的长度最大!
但是土豆片吸取了上次被白熊嘲笑的教训,看了看数据范围,好!2e5,暴力直接完蛋。
进一步思考:
题目与数组和数组子集和有关,自然能想到一个好用的东西——前缀和!!!
只需要找到预处理一下每个子集的和,特判总和小于s无解和等于s为0的情况,遍历找到最长的长度,最后用数组总长度减去子集最长的长度即可得到答案!
以下是代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,s;
int a[200005],b[200005];
void bluechips(){
cin>>n>>s;
int ans=0,num=0;
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=a[i]+b[i-1];
}
if(b[n]<s){
cout<<"-1"<<endl;
return ;
}
if(b[n]==s){
cout<<"0"<<endl;
return ;
}
for(int l=1;l<=n;l++){
for(int r=2;r<=n;r++){
if(b[r]-b[l-1]==s){
num=r-l+1;
ans=max(ans,num);
}
}
}
cout<<n-ans<<endl;
}
signed main(){
int t;
cin>>t;
while(t--){
bluechips();
}
return 0;
}
输入样例后结果:
完美!显然正确!土豆片自信a一发!
好!很好!又超时了!土豆片开始忧郁.......
最终实现:
在椒盐粉的安慰下,土豆片重拾信心再次开始尝试......
土豆片发现,使用了前缀和以后依然没有改变他使用暴力来找最长子集的事实,所以就应该从查找方式上进行修改,聪明的土豆片想到了双指针,或者二分两种方法。
经过仔细考虑,土豆片决定使用双指针来解决这个问题(要是用二分得换种方法写土豆片显然懒得干这种事)。
直接使用双指针来寻找保留部分的最大值!
#include <bits/stdc++.h>
#define int long long
using namespace std;
int a[200005];
void bluechips()
{
int n,k;
cin>>n>>k;
int sum = 0;
for(int i=1;i<=n;i++){
cin>>a[i];
sum+=a[i];
}
if(sum < k)
{
cout<<"-1"<<endl;; //特判
return;
}
int res=0;
int t=0;
for(int j=1,i=1;j<=n;j++)
{
t+=a[j];
while(i<j&&t>k){
t-=a[i++]; //灵魂双指针
}
if(t==k){
res=max(res,j-i+1); //直接找到最大值
}
}
cout<<n-res<<endl; //输出结果
}
signed main()
{
int t;
cin>>t;
while(t--)
bluechips();
return 0;
}
本着样例过了就是过了的原则(忘了是谁教的了)自信提交!
完结撒花*★,°*:.☆( ̄▽ ̄)/$:*.°★* 。
总结:
1.注意时间复杂度,在想到暴力做法时想办法优化。
2.双指针跟二分的搜索方法要进一步熟悉,多用提高熟练。