7 条题解

  • 1
    @ 2024-10-6 21:21:38

    题目大意

    给一个长度为 nn 的序列 aa,每次操作可以选择一个整数 ii ,在 aiai+1a_i \ne a_{i+1} 的情况下删除 ai+1a_{i+1} 并修改 aia_i,求共可以进行几次操作。

    思路

    通过观察样例可以发现,当序列中的每一项都相等时,是无法进行操作的,因为没有任意 ii 满足 aiai+1a_i \ne a_{i+1},此时答案为0。
    此外,只要有一个与其它项不同的项,那么我们可以操作到序列中仅有一个项,在这里放个图:
    可见其中 n1n - 1 个数都被删除了,则结果为 n1n - 1
    那么我们可以愉快地写代码啦!

    代码实现

    #include<bits/stdc++.h>
    using namespace std;
    int main(void) {
    	int n,a[100005]= {0},b,flag=1; //开的空间比数据范围大5是个好习惯
    	cin>>n>>a[1],b=a[1];
    	for(int i=2; i<=n; i++) {
    		cin>>a[i];
    		if(a[i]!=b)flag=0;
    	}
    	if(flag)cout<<0;
    	else cout<<n-1;
    	return 0;
    }
    
    • 1
      @ 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; 
      }
      

      写作不易,还请各位点赞支持一下。

      如有不足,还请指出,感谢各位观看。

      • -1
        @ 2024-8-4 18:58:04

        Description\textbf{Description}

        给你一个序列 a1,a2,,ana_1, a_2, \ldots, a_n。你可以对这个序列进行若干次操作。

        设一次操作前序列长度为 mm,那么这次操作你可以选择一个整数 ii 使得 1im11 \le i \le m - 1aiai+1a_i \ne a_{i + 1},删除 ai+1a_{i + 1} 并把 aia_i 的值设成任意整数

        求你最多能进行多少次操作。

        Solution\textbf{Solution}

        假设序列分为 x(xn)x\,(x\le n) 段,第 ii 段的数均为 tit_i,第 ii 段的长度为 lil_i

        此处

        • i=1xli=n\sum_{i=1}^{x}l_i=n
        • 对于 i[1,x1]\forall\,i\in[1,x-1]titi+1t_i\not=t_{i+1}

        那么序列 aa 可以表示为这样:

        $$a=\underbrace{t_1,t_1,\cdots,t_1}_{l_1\,\text{个}},\cdots\underbrace{t_x,t_x,\cdots,t_x}_{l_x\,\text{个}} $$

        容易发现,如果 x=1x=1,即 aa 数组全部都是一个数的话,那么是无法操作的,输出 00 即可。


        否则,序列至少存在 t1t_1t2t_2

        此时 t1t_1 可以与第 l1+1l_1+1 个数 t2t_2 消掉,得到一个数 pp

        由于可以将 aia_i 的值设为任意整数,那么 pZ\exist\,p\in\mathbb{Z},使得对于 i[1,x]\forall\,i\in[1,x],有 ptip\not=t_i

        那么可以用 pp 消掉第 l1+1nl_1+1\sim n 个数,此时序列可以变为:

        $$a=\underbrace{t_1,t_1,\cdots,t_1}_{l_1-1\,\text{个}},p $$

        由于 pt1p\not=t_1,所以从后向前消,最后序列可以变为

        a=pa=p

        容易发现,此时序列操作了 n1n-1 次。


        综上所述,分类讨论:

        • 如果 aa 由一个数构成,输出 00
        • 反之,输出 n1n-1

        Code\textbf{Code}

        #include <bits/stdc++.h>
        const int N = 1e5 + 10;
        
        int n, a[N];
        
        int main() {
          std::cin.tie(0)->sync_with_stdio(0);
          std::cin >> n;
          for (int i = 1; i <= n; ++i)
            std::cin >> a[i];
          for (int i = 2; i <= n; ++i) {
            if (a[i] != a[i - 1]) { // 发现不同的数字
              std::cout << n - 1 << std::endl;
              return 0;
            }
          }
          std::cout << 0 << std::endl; // 全部都相同
          return 0;
        }
        
        • -2
          @ 2024-9-18 21:58:44

          标题

          思路

          解题方法

          复杂度

          时间复杂度:

          添加时间复杂度, 示例: O(n)O(n)

          空间复杂度:

          添加空间复杂度, 示例: O(n)O(n)

          Code

          #include<bits/stdc++.h> #define maxn 100005 using namespace std;

          int n, ans; //ans计算操作数 int a[maxn]; queue 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; }

          • -2
            @ 2024-8-7 20:03:08

            J2B 题解

            部分分 Subtask 22:因为数字都相同,没有可以进行的操作,输出 00 即可。

            接下来思考满分做法。因为数字不同时一定有至少一次可操作的,可以先操作这个数,然后将前面的数修改为与前后的数都不相同的任意一个数,一直操作下去,最终数列一定只会余下一个数。此时共操作 n1n-1 次。

            代码:

            #include<iostream>
            using namespace std;
            int a[100001];
            int main()
            {
                int n;
                cin>>n>>a[1];
                for(int i=2;i<=n;i++)
                {
                    cin>>a[i];
                    if(a[i]!=a[i-1])return cout<<n-1,0;
                }
                cout<<0;
                return 0;
            }
            
            • -2
              @ 2024-8-6 21:56:28

              Turtle and Sequences题解

              思路

              先说一个错误的思路

              我一开始做的思路有点问题,把这道题当成了类似去重的题。 就是在输入的时候,如果输入的数与上一个数不同,就读入,否则跳过。最后数组内数的多少就是答案。 写完调试了老半天,好不容易把样例调试对了,交上去喜提53分。

              后来重新读了题,才发现貌似理解错了题目的意思。举一个例子。

              以下面样例为例:

              7
              1 3 3 3 3 2 1
              

              如果按照原来的思路,就会得到 33 的结果。但实际上,答案应该是 66。具体过程如下。 由于可以将值设成任意整数,那我们设 kk 为一个很大的整数。

              步骤见下:

              操作次数    数组
              1           1 3 3 3 3 k
              2           1 3 3 3 k+1
              3           1 3 3 k+2
              4           1 3 k+3
              5           1 k+4
              6           k+5
              

              当然步骤不是唯一的。

              由此可见,只要保证操作结束后得到的数与前面不同,就可以继续进行操作。操作了 n1n - 1 次。

              特殊情况

              当所有数都一样时,答案为 00,易证。

              Code

              #include<bits/stdc++.h>
              using namespace std;
              typedef long long ll;
              int n,flag,a[100005];
              int main()
              {
              	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
              	cin>>n>>a[1];
              	for(int i=2;i<=n;i++)
              	{
              		cin>>a[i];
              		if(a[i-1]!=a[i]) flag=1;
              	}
              	if(flag) cout<<n-1;
              	else cout<<0;
              	return 0;
              }
              

              写篇题解不容易,求点赞。不足请指出。

              • -2
                @ 2024-8-5 17:57:27

                题解 Turtle and Sequences

                思路

                可以用一个测试用例来找规律。 比如说有这几个数:
                1 1 4 5 1 4
                可以发现,只要遇到两个不同的数 xxyy, 可以保证操作结束后得到的新数跟所有的数不一样。 所以又可以跟其他的数进行操作了。

                所以只有这两个情况了:

                • 有一对不相同:总共 n1n - 1 次。
                • 都相同:总共执行了 00 次。

                解题方法

                只要遇到两个数不同,输出 n1n - 1,否则输出 00
                复杂度为O(n)O(n)

                Code

                #include <bits/stdc++.h>
                using namespace std;
                
                int a[100005];
                
                int main(){
                    int n;
                    cin >> n;
                
                    for (int i = 1; i <= n; i++) {
                        cin >> a[i];
                    }
                
                    int cnt = 0;
                    for (int i = n; i > 1; i--) {
                        if(a[i] != a[i - 1]) {
                            cnt = n - 1;
                            break;
                        }
                    }
                
                    cout << cnt << "\n";
                    
                    return 0;
                }
                
                • 1

                信息

                ID
                21
                时间
                1000ms
                内存
                512MiB
                难度
                2
                标签
                递交数
                1510
                已通过
                392
                上传者