题意:有n个玩具娃娃,编号为1 ~ n。要求一条链子上的娃娃必须满足编号小的娃娃套在编号大的娃娃上。规定两种操作:1、拆下编号最大的娃娃。2、将一条链上的娃娃套在一个没有套在任何其他链子上的娃娃上(有点绕)。意思就是比如有一条链1→2→4→5,你可以拆下5,然后变成两条链1→2→4和5,或者将这条链套在6上,但是6不能已经套在任何其他链子上,变成1→2→4→5→6。题目要求用最少的操作步数将所有的娃娃套在一个链子上。
想清楚了其实还是蛮简单的。每个娃娃最多只需要两次步骤——拆和套。我们可以这样想。编号为1的娃娃所在的那条链子上,1是不需要拆下来的。也就是不用进行任何操作。如果1套在2上,那么2也不用拆下来,再接着如果2套在3上,那么3也不用拆 ...... 以此类推,这条链上从1开始连续的数字都是不用拆的。直到某个地方不连续,比如1→2→3→4→6→7→8,其中4套在6上,那么5肯定在别的链子上,需要把6(包括6)以后的所有娃娃都拆下来,然后把5接上去,再把6 7 8接上去。由此看来,这条链上从1开始连续的数字不用拆。一旦遇到不连续,则从这个不连续的娃娃开始后面的全部都要拆。对于其他的链子,我们设编号最小的娃娃为A,因为它不是1,所以有比它更小的娃娃需要套在A上面,然而题目规定套娃娃的时候A不能已经套在其他的娃娃上,而A又是这条链上最小的娃娃,所以这条链上除了A以外的娃娃全部都要拆下来。由此看来,其他的链子上必须每条链子都完全拆卸。而每条链子上的最小的娃娃不用拆,但是需要套。对于需要拆的娃娃,必须要操作2次,即拆+套。对于不需要拆但需要套的娃娃,需要操作1次。对于既不用拆也不用套的娃娃,不需要操作。这样直接计算即可。可以证明这样肯定是最少的操作步数。一方面,这是至少需要的步数,另一方面,除了从1开始连续的数没被拆掉,剩下所有的娃娃都被拆成了单个。所以直接按编号顺序一个个套即可,不需要多余的步骤,因此这一定是最小步数的操作。
设编号为1的娃娃所在的链子上从1开始连续的数字一共有cnt个,那么答案为2*(n - cnt - (k - 1)) + 1*(k - 1) = 2*(n - cnt) - k + 1即公式。于是我们只需要求出cnt再用公式计算即可。
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <stack> #include <queue> #include <vector> #include <map> #include <set> using namespace std; const int MAX = 100005; int n, k; void solve() { int m, x, temp, cnt = 1, ans = 2*n - k + 1; bool flag; while(k--) { scanf("%d", &m); scanf("%d", &x); if(x == 1) flag = true; else flag = false; temp = x; while(--m) { scanf("%d", &x); if(x != temp + 1) flag = false; if(flag) cnt++; temp = x; } } printf("%d\n", ans - 2*cnt); } int main() { while(scanf("%d%d", &n, &k) != EOF) solve(); return 0; }