2 条题解
-
0
题意&思路
给定 ~ 的排列 ,和 ~ 的序列 和 ,求最少删除多少次(删除一次为同时删除 、、)使得 、、 中的元素相等。
首先统计 和 中缺少哪些数,假设 中缺少了一个 ,那么就要在 中找到 并把那一整列删除。如果这次删除导致了 或 中新增了缺少的元素,也要执行上面的删除步骤。需要注意:如果删除过了 后面就不能再删 ,否则 中就会没有 删。 重复上述过程直到 、 和 中的元素相同。
我们可以使用一个顺序表来存储缺少的数字,队列自然最优。当队列为空时说明 和 相对 不再缺少元素,此时就输出删除的次数,程序结束。
复杂度方面是 级别的,虽然常数很大但 的数据范围对于 还是很友好的,不会超时。
AC Code
实现时需要作不少的预处理,如记录下 ~ 在 中的位置, 和 中数字出现的次数等。
#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
第一列由于每个数字只会出现一次 我们可以用 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
- 上传者