CF思维训练回顾
文章目录
- 前言
- 1. Collecting Game
- 2.Save the Magazines
- 3.Food Buying
- 总结
前言
这里讲述了写的800——1100分数的题中写错过的题,对于这些题还是要多思考
1. Collecting Game
这题题意很明显,就是考虑从每一个数开始,找出相应的能够移除的最多元素个数
当时就想着要对每一个数都要进行一次查找,没有想到更好的方法,或者说开始没有深入思考用其他方法写(前缀和优化),然后白给一发后才想着深入思考前缀和(后面会具体解释),后来就过了
白给代码:
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define pii pair<int,int>
#define fi first
#define se second
#define int long long
#define endl '\n'
const int N=1e5+6;
int a[N];
signed main()
{int t;cin>>t;while(t--){int n;cin>>n;vector<int>ve;for(int i=1;i<=n;i++){cin>>a[i];ve.push_back(a[i]);}for(int i=0;i<ve.size();i++){vector<int>ve1=ve;int x=ve1[i];ve1.erase(ve1.begin()+i,ve1.begin()+i+1);sort(ve1.begin(),ve1.end());int sum=0;for(int j=0;j<ve1.size();j++){if(x>=ve1[j]){sum++;x+=ve1[j];}else{break;}}cout<<sum<<" ";}cout<<endl;}return 0;
}
正确用前缀和优化代码:
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define pii pair<int,int>
#define fi first
#define se second
#define int long long
#define endl '\n'
const int N=1e5+6;
int a[N];
int b[N]={0};//前缀和数组
int c[N];//记录最终每个数能够移除的数量
signed main()
{int t;cin>>t;while(t--){int n;cin>>n;vector<pii>ve;for(int i=1;i<=n;i++){cin>>a[i];ve.push_back({a[i],i});}sort(ve.begin(),ve.end());//对元素排序,方便后续操作memset(b,0,sizeof(b));b[0]=ve[0].fi;for(int i=1;i<ve.size();i++){b[i]=b[i-1]+ve[i].fi;//前缀和操作}vector<int>ve1;//存储截止点(就是前n项都会在这个截止点停止,后面就没有其能够移除的数)for(int i=1;i<ve.size();i++){if(ve[i].fi>b[i-1]){ve1.push_back(i);}}int x=0;for(int i=0;i<ve1.size();i++)//遍历每一个截止点{for(int j=x;j<ve1[i];j++)//遍历两个截止点之间的数,因为这个区间内其移除数都为ve1[i]-1{c[ve[j].se]=ve1[i]-1;}x=ve1[i];}for(int i=x;i<ve.size();i++){c[ve[i].se]=n-1;//最后几个数可能没有明显截止点,所以此时n就为其截止点}for(int i=1;i<=n;i++){cout<<c[i]<<" ";}cout<<endl;}
}
2.Save the Magazines
这题也是非常的不友好,如果只考虑相邻两个是错误的,只考虑有盖子区间与移动后的盖子区间也会错误,所以只有将前一个无盖子的数有与有盖子区间的数相结合,求在与有盖子区间的数量的限制下能够得到的最大值。
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define pii pair<int,int>
#define fi first
#define se second
#define int long long
#define endl '\n'
const int N=2e5+6;
int a[N];
signed main()
{int t;cin>>t;while(t--){int n;cin>>n;string s;cin>>s;for(int i=0;i<n;i++){cin>>a[i];}int l,r;int minn=INT_MAX;int sum=0;bool vis=0;for(int i=0;i<s.size();i++){if(s[i]=='1')//有盖子的{sum+=a[i];if(vis==1)//要参与组成数组{minn=min(minn,a[i]);//取最小}} else//无盖子的{if(vis==1){sum-=minn;//减去组成区间内的最小值minn=INT_MAX;//重新将其赋值为了后续操作vis=0;//重新将其赋值为了后续操作}if(s[i+1]=='1'&&i<s.size()-1)//其后面是有盖子的,此时就可以操作{sum+=a[i];//将该数也加入,最后在减去组成区间内的最小值就达到了最大要求minn=min(minn,a[i]);//取最小vis=1;//相当于一个标记,此时后面有盖子的才能判断是否要参与该组成数组}}}if(vis==1){sum-=minn;}cout<<sum<<endl;}return 0;
}
3.Food Buying
看完这题就想着用15或者是来进行大部分操作,但是给的题解是利用10进行大部分操作,就很懵,后来就按照10来暴力写,虽然过了,但是还是有点懵
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define pii pair<int,int>
#define fi first
#define se second
#define int long long
#define endl '\n'
signed main()
{int t;cin>>t;while(t--){int s;cin>>s;int sum=0;while(s>0){ if(s>=100000)//简单暴力{s-=100000;sum+=100000;s+=10000;}if(s>=10000){s-=10000;sum+=10000;s+=1000;}if(s>=1000){s-=1000;sum+=1000;s+=100;}if(s>=100){s-=100;sum+=100;s+=10;}if(s>=10){s-=10;sum+=10;s+=1;}if(s<10){sum+=s;s-=s;}}cout<<sum<<endl;}return 0;
}
总结
这次练习了许多道800——1100的题,确实有助于思维练习,要是不仔细看或者仔细想,可能就找不到解题方法,或者是想错方向。