C. Garland - DP 贪心

C. Garland

time limit per test

1 second

memory limit per test

256 megabytes

input

standard input

output

standard output

Vadim loves decorating the Christmas tree, so he got a beautiful garland as a present. It consists of nn light bulbs in a single row. Each bulb has a number from 11 to nn (in arbitrary order), such that all the numbers are distinct. While Vadim was solving problems, his home Carp removed some light bulbs from the garland. Now Vadim wants to put them back on.

Vadim wants to put all bulb back on the garland. Vadim defines complexity of a garland to be the number of pairs of adjacent bulbs with numbers with different parity (remainder of the division by 22). For example, the complexity of 1 4 2 3 5 is 22 and the complexity of 1 3 5 7 6 4 2 is 11.

No one likes complexity, so Vadim wants to minimize the number of such pairs. Find the way to put all bulbs back on the garland, such that the complexity is as small as possible.

Input

The first line contains a single integer nn (1≤n≤1001≤n≤100) — the number of light bulbs on the garland.

The second line contains nn integers p1, p2, …, pnp1, p2, …, pn (0≤pi≤n0≤pi≤n) — the number on the ii-th bulb, or 00 if it was removed.

Output

Output a single number — the minimum complexity of the garland.

Examples

input

Copy

5
0 5 0 2 3

output

Copy

2

input

Copy

7
1 0 0 5 0 0 2

output

Copy

1

Note

In the first example, one should place light bulbs as 1 5 4 2 3. In that case, the complexity would be equal to 2, because only (5,4)(5,4) and (2,3)(2,3) are the pairs of adjacent bulbs that have different parity.

In the second case, one of the correct answers is 1 7 3 5 6 4 2.

==

=========================================================================

很有思维价值的一道题目,首先考虑0段的分类,无非三类

结尾开头行 即 000x   , x000类型 ,

两段不同型 即 奇0000偶

两端相同型 即 偶0000偶

分别对这三种情况进行研究,第一种的情况,若全部与x奇偶性相同,则必定贡献0,否则一定是1,绝对不会是2

第二种情况,易知最差最坏都是1,无论几个偶数几个奇数

第三种情况,易知最好是0,最差就是2,且只有2这一种情况

那么就显而易见了,很重要的一点就是题目问的是数目,注意是数目,也就是不要往构造出这一整个序列方面去想。

由于第二种情况已经确定,故我们只需要暴力求解第一第三即可

设dp[i][j][k]为 前i段 ,使用了j个奇数,k个偶数时的最小答案, 枚举i,j,k与当前的奇数选择个数即可

还要加上之前就有的,外加第二种情况的个数,细节很多,但理解之后就很容易调试了

# include<bits/stdc++.h>

using namespace std;
# define mod 1000000007
typedef long long int ll;

vector<int>v1,v2;
int book[1000],a[1000];

struct node
{
    int ji;
    int len;
    int add;

};

struct node s[1000];

int dp[110][110][110];

int main ()
{
  int n;
  cin>>n;

  for(int i=1;i<=n;i++)
  {
      cin>>a[i];

      book[a[i]]=1;
  }



  int cnt1=0,cnt2=0;
  for(int i=1;i<=n;i++)
  {
      if(book[i]==0)
      {
          if(i%2==1)
          {
              cnt1++;
          }
          else
          {
              cnt2++;
          }
      }
  }

  if(cnt1+cnt2==n)
  {
       if(n==1)
       {
           cout<<0;

       }
       else
       {
           cout<<1;
       }
      return 0;
  }

  int pos=1,len=0;
  int temp=0;
  while(a[pos]==0)
  {
      temp++;
      pos++;
  }
  int pos1=pos;

  if(temp)
  {
      len++;
      s[len].ji=a[pos]%2;
      s[len].len=pos-1;
      s[len].add=1;

  }

  pos=n,temp=0;

  while(a[pos]==0)
  {
      temp++;
      pos--;
  }

  int pos2=pos;

  if(temp)
  {
      len++;
      s[len].ji=a[pos]%2;
      s[len].len=n-pos;
      s[len].add=1;

  }

  int yu=0,fuckcnt=0;


  for(int i=1;i<=n;i++)
  {
      if(a[i]!=a[i+1])
      {
          if(a[i]!=0&&a[i+1]!=0)
          {
              if(a[i]%2!=a[i+1]%2)
                yu++;
          }
      }
  }

  for(int i=pos1;i<pos2;i++)
  {


      if(a[i]&&a[i+1]==0)
      {

          //分段

          int tempcnt=0;
          for(int j=i+1;j<pos2;j++)
          {
              if(a[j]==0)
              tempcnt++;
              else
                break;

          }
          int nex=i+tempcnt+1;

          if(a[nex]%2!=a[i]%2)
          {
              fuckcnt+=tempcnt;
              yu++;
          }
          else
          {
              len++;
              s[len].ji=a[nex]%2;
              s[len].len=tempcnt;
              s[len].add=2;


          }
          i=nex-1;
      }
  }

//  前i段耗费多少cnt1,多少cnt2,得到的最小值

for(int i=0;i<=n;i++)
{
    for(int j=0;j<=n;j++)
    {
        for(int k=0;k<=n;k++)
        {
            dp[i][j][k]=1e9;
        }
    }
}


dp[0][0][0]=0;

for(int i=1;i<=len;i++)
{

    for(int j=0;j<=cnt1;j++)
    {
        for(int k=0;k<=cnt2;k++)
        {

            for(int now1=0;now1<=j;now1++)
            {


                //枚举我当前使用了多少1

                int now2=s[i].len-now1;
                //枚举我当前用了多少2

                if(now2>k||now2<0)
                    continue;

                //不合法

                if(s[i].ji==1&now1==s[i].len)
                {
                    dp[i][j][k]=min(dp[i][j][k],dp[i-1][j-now1][k-now2]);
                }
                else if(s[i].ji==0&&now2==s[i].len)
                {
                       dp[i][j][k]=min(dp[i][j][k],dp[i-1][j-now1][k-now2]);

                }
                else
                {
                       dp[i][j][k]=min(dp[i][j][k],dp[i-1][j-now1][k-now2]+s[i].add);
                }
            }
        }
    }
}

int ans=1e9;
for(int i=0;i<=cnt1;i++)
{
    for(int j=0;j<=cnt2;j++)
    {
        if((i+j)==cnt1+cnt2-fuckcnt)
        {
            ans=min(ans,dp[len][i][j]);
        }
    }
}


cout<<ans+yu;
    return 0;

}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秦三码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值