CF 1173C Nauuo and Cards

题目链接

题目大意

一共有2*n张牌,n张0,n张1到n。现在随机的n张(有0有数字)在手上,另n张再牌堆中,现在已知手上的牌和牌堆的牌,可以进行多次以下操作:将手中任意一张牌放入牌堆底,将牌堆顶的一张牌放入手中。问最少多少次后可使牌堆顶到牌堆底的n张牌分别为1,2,3...n。

思路

首先,要完成最后的状态,可以每次都放0,直到所有数字都在手上(因为0的张数与数字的张数都是n,所以一定可以用0把所有数字都换出来),再依次放入牌堆。

可以减少次数的地方有两个:

  • 有些牌直接在牌堆里就可以,不用再手中倒一下。(例如,原题中的第一个例子,1在所有操作时都在牌堆中。)
  • 不一定要等到所有的牌都在手中才开始按顺序放入牌堆,也就是说,换出 i 不一定全用0。

第一个,我可能没想到什么好方法,特殊讨论一下,看能不能直接放完。

第二个,最终放入堆底牌的顺序一定是 0,···,0,1,2,···,n,因此关键是考虑有多少个0。计算出每张数字牌换到手中本来需要的0的张数p[i],这些0中最多有i-1个都能变成数字,因此要使得 i 在开始放数字时顺利,就最少需要放 p[i]-i+1 张0。所以,找出放0最多的,再加n就好。

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 int shou[200005],dui[1000006],hd,tl,ans,p[200005],n,inshou[200005];
 6 
 7 bool paixu()
 8 {
 9     bool ret=1;
10     for(int i=1;i<=n;i++)
11     {
12         if(i!=dui[i+hd])ret=0;
13     }
14     return ret;
15 }
16 
17 void workp()
18 {
19     for(int i=1;i<=n;i++)
20     {
21         p[shou[i]]=0;
22     }
23     for(int i=1;i<=n;i++)
24     {
25         p[dui[i]]=i;
26     }
27     return ;
28 }
29 
30 int main()
31 {
32     scanf("%d",&n);
33     for(int i=1;i<=n;i++)
34     {
35         scanf("%d",&shou[i]);
36         inshou[shou[i]]++;
37     }
38     for(int i=1;i<=n;i++)
39     {
40         scanf("%d",&dui[i]);
41     }
42     hd=0;tl=n;
43     while(inshou[dui[tl]+1])
44     {
45         ans++;
46         tl++;
47         dui[tl]=dui[tl-1]+1;
48         inshou[dui[tl]]--;
49         hd++;
50         inshou[dui[hd]]++;
51     }
52     if(paixu())
53     {
54         printf("%d\n",ans);
55         return 0;
56     }
57     else
58     {
59         ans=0;
60         workp();
61         for(int i=1;i<=n;i++)
62         {
63             ans=max(ans,p[i]-i+1);
64         }
65         ans+=n;
66     }
67     printf("%d\n",ans);
68     return 0;
69 }

猜你喜欢

转载自www.cnblogs.com/LiqgNonqfu/p/10990238.html