9 条题解

  • 6
    @ 2024-6-29 18:43:11

    S001A. 壁垒

    Statement\mathsf{\color{Plum}Statement}

    给定一个长度为 nn 的序列 aa,是否存在一种重排方式使得每个长度为偶数的前缀,出现的数字种类数为偶数。若存在,输出方案;否则,输出 -1

    Solution\mathsf{\color{Plum}Solution}

    若整个序列的数字种类数为奇数,则不存在方案;否则,必定存在一种方案

    • 如果整个序列的数字种类数是奇数,那么第 nn 位(题目中保证了 nn 为偶数)的数字种类数必定不是偶数
    • 如果整个序列的数字种类数是偶数(令其为 mm),那么只需将前 mm 个位置放置 每种数字,后面随便放置即可(这样,即可保证前 mm 个位置,相邻偶数位每次加 22,后面恒定不变)。

    综上所述,即可在 O(n)O(n) 的时间复杂度下 AC\mathsf{\color{green} AC} 此题。

    Code\mathsf{\color{Plum}Code}

    signed main() {
    	cin.tie(0);
    	cout.tie(0);
    	ios::sync_with_stdio(0);
    
    	cin >> n;
    	unordered_map<int, int> cnt;
    	for (int i = 1; i <= n; i ++)
    		cin >> a[i], cnt[a[i]] ++;
    
    	if (cnt.size() & 1) cout << -1 << endl;
    	else {
    		for (auto v : cnt)
    			cout << v.fi << " ";
    		for (auto v : cnt) {
    			int tot = v.se - 1;
    			while (tot -- ) cout << v.fi << " ";
    		}
    		cout << endl;
    	}
    
    	return 0;
    }
    
    • 4
      @ 2024-6-29 18:08:57

      签到题。

      aa 中不同元素的个数为 ss,若 ss 为奇数,易知不存在解。

      考虑 ss 为偶数,此时定存在一种顺序使 aa 的前 ss 个元素互不相同,此时第 ss 个元素之后的每一个元素都已出现过,不会对元素种类产生影响,符合题意。

      AC 代码:

      #include <bits/stdc++.h>
      using namespace std;
      #define int long long
      #define len 214514
      int n, a[214514], s;
      map <int, bool> v;
      signed main() {
      	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
      	cin >> n;
      	for (int i = 1; i <= n; i++) { 
      		cin >> a[i]; 
      		if (!v[a[i]]) v[a[i]] = 1, s++;
      	}
      	if (s % 2) { cout << -1; return 0; }
      	v.clear();
      	for (int i = 1; i <= n; i++) if (!v[a[i]]) cout << a[i] << ' ', v[a[i]] = 1, a[i] = -1;
      	for (int i = 1; i <= n; i++) if (a[i] != -1) cout << a[i] << ' ';
      	return 0;
      }
      
      • -1
        @ 2024-7-5 11:59:49

        考察知识点: 构造法

        首先考虑无解的情况,因为 nn 是偶数,所以当数列中出现了 xx 种不同的数字,且 xx 为奇数时,无解,输出 1-1

        接着就是有解的情况,把 xx 个数字全都输出,由于 xx 是偶数,且每个数字有且仅有出现了 11 次,所以偶数个数字构成的序列中数字种类数必定为偶数。所有的都输出完毕了,后面只可能出现 xx 种数字,而 xx 又是偶数,所以可以直接按顺序直接输出。

        Code:

        #include <bits/stdc++.h>
        using namespace std;
        int a[100005];
        int main()
        {
            memset(a,0,sizeof a);
            int n,s = 0,ma = 0,x;
            cin >> n;
            for (int i = 1;i <= n;i++)
            {
                cin >> x;
                ma = max(ma,x);
                if (a[x] == 0) s++;
                a[x]++;
            }
            if (s % 2 == 1) 
            {
                cout << -1;
                return 0;
            }
            for (int i = 1;i <= ma;i++)
            {
                if (a[i] >= 1) 
                {
                    cout << i << ' ';
                    a[i]--;
                }
            }
            for (int i = 1;i <= ma;i++)
            {
                if (a[i] >= 1)
                {
                    for (int j = 1;j <= a[i];j++)
                    {
                        cout << i << ' ';
                    }
                }
            }
            return 0;
        }
        
        • -1
          @ 2024-6-29 18:07:08

          思路

          设总共有 kdskds 种。

          首先考虑无解

          因为 nn 一定是偶数,所以如果 kdskds 是个奇数,不管你怎么排,有 nn 个数的数列一定是奇数种。

          综上,当 kdskds 为奇数时,直接 1-1

          有解的情况

          思路也很简单。因为我们判断了 kdskds 为偶数,所以只需要第一次把每种都打出来一个,前面偶数个必定没问题。后面你随意,因为所有种类都输出了,你怎么搞都行。

          Code

          #include<bits/stdc++.h>
          using namespace std;
          int n,a,b[100005],kds,mx=-1;
          int main()
          {
              cin>>n;
              for(int i=0;i<n;++i)
              {
                  cin>>a;
                  mx=max(mx,a);
                  if(b[a]==0)
                  {
                      kds++;
                  }
                  ++b[a];
              }
              if(kds%2==1)
              {
                  cout<<-1;
                  return 0;
              }
              kds=0;
              int i=1,nn=n;
              while(n>0)
              {
                  if(b[i]!=0)
                  {
                      cout<<i<<" ";
                      b[i]--;
                      n--;
                  }
                  ++i;
                  if(i>mx)
                  {
                      i=1;
                  }
              }
              return 0;
          }
          
          • -2
            @ 2024-7-27 9:00:59

            S1A 题解

            第四篇题解。

            此题是构造题。因为序列的单调递增序列一定包含了这个序列的所有元素,所以我们这个序列剩下的一定是重复的元素,又因为重复的元素不影响数字的种类,所以我们把它们放在后面输出。首先判断无解的情况,然后构造序列的单调递增序列并输出,接着将剩下的元素输出即可。

            代码:

            #include<iostream>
            using namespace std;
            int a[100001];
            int main()
            {
                int n,t=0;
                cin>>n;
                for(int i=1;i<=n;i++)
                {
                    int b;
                    cin>>b;
                    a[b]++;
                    if(a[b]==1)t++;
                }
                if(t%2)cout<<-1;
                else
                {
                    for(int i=1;i<=n;i++)if(a[i])a[i]--,cout<<i<<' ';
                    for(int i=1;i<=n;i++)while(a[i]--)cout<<i<<' ';
                }
                return 0;
            }
            
            • -2
              @ 2024-7-13 9:16:02

              转化一下题意:无法找到一个偶数 ii 使得构造出来的序列的第 1i1\sim i 项所有元素的出现次数为奇数。

              结论:若 1n1\sim n 的种类数为奇数,那么一定无法构造出来。

              证明:很显然,我们取 iinn 即可。

              那么我们可以把 aa 中所有出现过的数都输出一遍,然后接下来去掉刚刚出现过的数,然后随便输出即可。

              证明一下这个构造。

              我们设 aa 中有 xx 个不同的数,那么因为 xx 不为奇数,按这样构造前 xx 个一定满足要求。

              而后 nxn-x 个的每个数因为都在前 xx 个出现过了,那么后 nxn-x 个也满足要求。

              那么我们就直接模拟即可:

              #include<bits/stdc++.h>
              using namespace std;
              
              const int N=1e5+5;
              int n;
              int a[N];
              vector<int> v;
              map<int,int> mp;
              
              signed main(){
              	ios::sync_with_stdio(0);cin.tie(0);
              	cin>>n;
              	for(int i=1;i<=n;i++){
              		cin>>a[i];
              		mp[a[i]]++;
              	}
              	if(mp.size()%2){
              		cout<<-1;
              		return 0;
              	}
              	sort(a+1,a+n+1);
              	for(int i=1;i<=n;i++){
              		if(mp[i]){
              			cout<<i<<' ';
              			for(int j=1;j<mp[i];j++) v.push_back(i);
              		}
              	}
              	for(int i:v) cout<<i<<' ';
              	return 0;
              }
              
              • -2
                @ 2024-7-9 21:44:11

                题解: S001A 壁垒

                传送门

                思路&解题方法

                首先发现如果种类数本身为奇数,则一定无解(整个数列也算一个前缀)

                发现可以对构造出来的数列进行分析。前缀两个两个地增加,不难发现,每次要么增加 00 种数字,要么增加 22 种数字。

                构造时,可以先将偶数种数字依次用一遍(每次增加 22 种),然后就随便放了,因为剩下的数字前面都出现过,每次只有可能增加 00 种数字。

                所以,在种类数为偶数时,肯定有解。

                复杂度

                时间复杂度:

                O(n)O(n)

                空间复杂度:

                O(n)O(n)

                Code

                #include<bits/stdc++.h>
                using namespace std;
                const int N=100005;
                int times[N];
                vector<int>ans;
                
                int main() {
                    int n, m=0;
                    scanf("%d", &n);
                    for(int i=0; i<n; i++) {
                        int x;
                        scanf("%d", &x);
                        ++times[x];
                        if(times[x]==1)
                            ++m; // 用m记录种类数
                    }
                    if(m%2)
                        return printf("-1\n")&0; // 无解的情况
                    for(int i=1; i<=n; i++) {
                        if(times[i]==0)
                            continue;
                        printf("%d ", i);
                        --times[i];
                    } // 第一遍,每个种类都消耗一遍,增加2种数字
                    for(int i=1; i<=n; i++) {
                        while(times[i]) {
                            --times[i];
                            printf("%d ", i);
                        }
                    } // 第二遍,每次总是增加0种数字
                    puts("");
                    return 0;
                }
                
                
                • -3
                  @ 2024-7-10 13:08:25

                  标题

                  思路

                  容易证明只需要去重并构造单调递增序列即可。

                  解题方法

                  同上。

                  复杂度

                  时空复杂度:O(n)O(n)

                  • -4
                    @ 2024-7-10 13:07:51

                    标题

                    思路

                    容易证明只需要去重并构造单调递增序列即可。

                    解题方法

                    同上。

                    复杂度

                    时空复杂度:O(n)O(n)

                    Code

                    • 1

                    信息

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