7 条题解

  • 0
    @ 2024-8-4 21:42:31

    我们可以从前往后模拟一遍,寻找思路。

    这里使用样例三进行分析。

    输入:1 1 45 14。 输出:3

    模拟过程:

    第一次:到第三项时,删除 4545,将 11 改为 22

    第二次:删除这个 22,将 11 改为 1313

    第三次:删除 1414,把 1313 改为 22,就结束操作了。


    那么,我们发现,这是一个线性进行的过程,这让我想起了一个数据结构——队列。我们可以用队列来模拟这个过程。


    我的思路:从第一项开始,将暂时删不掉的项入队(由于删不掉的必然与前一项相等,所以能保留在队列中的所有项都一定相等),接着当队尾遇到能被删除的项(就是与队尾不相等的项)时,立刻开始执行操作。

    因为之前能保留在队列中的所有项都相等,那么当我们追求最优,修改队尾的值时,队列中的所有项都可以被修改,那么此时还会有一个被修改的项存在队列里。我们不必关心此时它的值,因为它可以修改成任意整数,这就意味着从它开始,这个队列就只可能存在一个项,再往后模拟时,就只要一次一次加操作数就行了。

    因为它是任意的,所以之后的项肯定都会被其删掉。这道题就这样解决掉了。

    由于每一项至多入队一次,所以时间复杂度为 O(n)O(n),完全足以过掉这道题。详情见代码注释。

    接下来是代码时间(代码比较拙劣,见谅)。

    #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
    上传者