7 条题解
-
0
我们可以从前往后模拟一遍,寻找思路。
这里使用样例三进行分析。
输入:
1 1 45 14
。 输出:3
。模拟过程:
第一次:到第三项时,删除 ,将 改为 ;
第二次:删除这个 ,将 改为 ;
第三次:删除 ,把 改为 ,就结束操作了。
那么,我们发现,这是一个线性进行的过程,这让我想起了一个数据结构——队列。我们可以用队列来模拟这个过程。
我的思路:从第一项开始,将暂时删不掉的项入队(由于删不掉的必然与前一项相等,所以能保留在队列中的所有项都一定相等),接着当队尾遇到能被删除的项(就是与队尾不相等的项)时,立刻开始执行操作。
因为之前能保留在队列中的所有项都相等,那么当我们追求最优,修改队尾的值时,队列中的所有项都可以被修改,那么此时还会有一个被修改的项存在队列里。我们不必关心此时它的值,因为它可以修改成任意整数,这就意味着从它开始,这个队列就只可能存在一个项,再往后模拟时,就只要一次一次加操作数就行了。
因为它是任意的,所以之后的项肯定都会被其删掉。这道题就这样解决掉了。
由于每一项至多入队一次,所以时间复杂度为 ,完全足以过掉这道题。详情见代码注释。
接下来是代码时间(代码比较拙劣,见谅)。
#include<bits/stdc++.h> #define maxn 100005 using namespace std; int n, ans; //ans计算操作数 int a[maxn]; queue<int> q; int main() { ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); cin>>n; bool ok=1; for(int i=1;i<=n;i++) { cin>>a[i]; if(i!=1&&a[i]!=a[i-1])ok=0; } if(ok) {//如果每一项都相等,就操作不了,输出0,对应第2个子任务 cout<<0;return 0; } if(n<=2) {//一个小特判,对应第一个子任务 if(n==1) cout<<0; //只有一项无法操作,输出0 else cout<<1; //此时两项必然不相等,可以操作一次 return 0; } bool flag=0; //存储队首是否参与操作 for(int i=1;i<=n;i++) { if(q.empty())q.push(a[i]);//如果队列为空就加入 else if(a[i]==q.front()&&!flag)q.push(a[i]); //如果和队首相等就删不了,要加入,但是如果队首之前参与过操作,这一项也得删除 else { ans++; //要删,操作数加1 while(q.size()>1){ //一次性操作到只剩一个 flag=1; q.pop(); ans++; } } } cout<<ans; //输出,一次过 return 0; }
写作不易,还请各位点赞支持一下。
如有不足,还请指出,感谢各位观看。
信息
- ID
- 21
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 2
- 标签
- 递交数
- 1499
- 已通过
- 386
- 上传者