2 条题解

  • 0
    @ 2024-4-18 21:51:33

    题意&思路

    给定 11~nn 的排列 aa,和 11~nn 的序列 bbcc,求最少删除多少次(删除一次为同时删除 aia_ibib_icic_i)使得 aabbcc 中的元素相等。

    首先统计 bbcc 中缺少哪些数,假设 bb 中缺少了一个 xx,那么就要在 aa 中找到 xx 并把那一整列删除。如果这次删除导致了 bbcc 中新增了缺少的元素,也要执行上面的删除步骤。需要注意:如果删除过了 xx 后面就不能再删 xx,否则 aa 中就会没有 xx 删。 重复上述过程直到 aabbcc 中的元素相同。

    我们可以使用一个顺序表来存储缺少的数字,队列自然最优。当队列为空时说明 bbcc 相对 aa 不再缺少元素,此时就输出删除的次数,程序结束。

    复杂度方面是 O(n)O(n) 级别的,虽然常数很大但 10510^5 的数据范围对于 O(n)O(n) 还是很友好的,不会超时。

    AC Code

    实现时需要作不少的预处理,如记录下 11~nnaa 中的位置,bbcc 中数字出现的次数等。

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const ll N=1e5+5;
    ll n,a[N],mp[N],b[N],c[N],cb[N],cc[N],ans;
    // mp表示1~n在a中的位置,cb和cc分别表示b和c中数字出现的次数
    queue<ll> q;
    int main(){
        scanf("%lld",&n);
        for(ll i=1;i<=n;i++)
            scanf("%lld",&a[i]),mp[a[i]]=i;
        for(ll i=1;i<=n;i++)
            scanf("%lld",&b[i]),cb[b[i]]++;
        for(ll i=1;i<=n;i++)
            scanf("%lld",&c[i]),cc[c[i]]++;
        for(ll i=1;i<=n;i++)
            if(cb[i]==0||cc[i]==0)
                q.push(i); // 将初始缺少的数字添加到队列中
        while(!q.empty()){
            ll k=q.front(); // 取出队首
            q.pop();
            if(mp[k]!=-1){ // 当队首没有被删除过
                ans++; 
                cb[b[mp[k]]]--,cc[c[mp[k]]]--; // 将对应列b和c中的元素删除
                // 如果这次删除造成了b或c中缺少了数字,就将缺少的数字加入队列中
                if(cb[b[mp[k]]]==0)
                    q.push(b[mp[k]]);
                if(cc[c[mp[k]]]==0)
                    q.push(c[mp[k]]);
                mp[k]=-1; // 记录k被删除过了
            }
        }
        printf("%lld",ans);
        return 0;
    }
    
    • 0
      @ 2024-4-12 19:55:18

      第一列由于每个数字只会出现一次 我们可以用 3 个桶去维护每行的数字出现次数 我们可以用3个桶去维护每行的数字出现次数我们可以用3个桶去维护每行的数字出现次数 第 1 行的某个数字,第 2 或第 3 行没有出现,第一行那个数对应的列,删掉 3 个数 第1行的某个数字,第2或第3行没有出现,第一行那个数对应的列,删掉3个数1行的某个数字,第2或第3行没有出现,第一行那个数对应的列,删掉3个数

      #include<bits/stdc++.h>
      using namespace std;
      
      const int maxn=1e5+10;
      int n,ans;
      int cnt1[maxn],cnt2[maxn],cnt3[maxn];
      int a[5][maxn];
      int main(){
      	scanf("%d",&n);
      	for(int i=1;i<=3;i++){
      		for(int j=1;j<=n;j++){
      			scanf("%d",&a[i][j]);
      			if(i==1)cnt1[a[i][j]]++;
      			else if(i==2)cnt2[a[i][j]]++;
      			else cnt3[a[i][j]]++;
      		}
      	}
      	while(1){
      		bool flag=true;
      		for(int i=1;i<=n;i++){
      			if(cnt1[i]==cnt2[i]&&cnt2[i]==cnt3[i])flag=true;
      			else {
      				flag=false;
      				break;
      			}
      		}
      		if(flag)break;
      		for(int i=1;i<=n;i++){
      			if(!cnt1[a[1][i]])continue;
      			if(!cnt2[a[1][i]]||!cnt3[a[1][i]]){
      				cnt2[a[2][i]]--;
      				cnt3[a[3][i]]--;
      				cnt1[a[1][i]]&=0;
      				ans++;
      			}
      		}
      	}
      	printf("%d\n",ans);
      	return 0;
      } 
      
      
      • 1

      信息

      ID
      708
      时间
      1000ms
      内存
      32MiB
      难度
      4
      标签
      递交数
      104
      已通过
      52
      上传者