CF1773E Easy Assembly
题意:
有许多积木,按堆竖直存放,可以进行两个操作:
- 1.分裂:从将一堆积木(数量大于 1)的顶端拿出若干块,按原来的顺序放在地上形成一堆新的积木。操作后积木堆数加一;
- 2.合并:将一堆积木全部按原来的顺序全部堆到另一堆积木的顶端。操作后积木堆数减一。
让所有木块形成一堆且积木上的数字由顶端到底端升序排列。求出最小操作次数。
思路:
最后合成的积木的情况是唯一的(因为题中要求了排序),将原来的积木状态与最后的积木状态进行遍历对应,对于某一个积木,如果当前元素大于下一个元素或者下一个元素不是比他大的最小的元素的话,需要进行分裂。最后将所有的积木堆进行合并操作即可。
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=0x3f3f3f3f;
vector<int> q[100010];
int a[100010];
map<int,int> mp;
void solve()
{
int n;
cin>>n;
int cnt=0;
for(int i=0;i<=n-1;++i)
{
int len;
cin>>len;
for(int j=1;j<=len;++j)
{
int x;
cin>>x;
q[i].push_back(x);
a[++cnt]=x;
}
}
sort(a+1,a+cnt+1);
for(int i=1;i<=cnt;++i)
mp[a[i]]=i;
int w=0,u=0;
for(int i=0;i<=n-1;++i)
{
w++;
for(int j=0;j<q[i].size()-1;++j)
{
if(a[mp[q[i][j]]+1]!=q[i][j+1]||q[i][j]>q[i][j+1])
{
w++;
u++;
}
}
}
cout<<u<<" "<<w-1<<endl;
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
solve();
return 0;
}