• CodeForces743E. Vladik and cards 二分+状压dp


    这个题我们可以想象成_---___-----__的一个水柱它具有一遍优一遍行的性质因此可以用来二分最小值len,而每次二分后我们都要验根,we可以把这个水柱想成我们在每个数段里取前一段的那个数后一段有也不选,而且最后一个区间的第一个数一定可以使这个数区间对应的数,那么我们只要在某个位置上不选或选就可以啦,这we很容易想到2n的验根但是这样还不如打暴力,这时我们发现这个dfs是低效的他会很多进入等效状态这样的话我们就可以记忆化搜索了,那么何妨递推,由于我们知道f[pos][mask]中只要pos(位置),mask(二进制代表是否选过)确定那么就要他的最大值就行了,而状态转移分两种一是前面len或len+1,或前一个状态,那么只要每一个状态是最大值,那么我们就从前面推到最后就找到了,这样的话我们可以正向推来代替反向吸收,因为如果只有那样吸收也就只有那样推.

    千万不要忘了0的特判以及状态转移的完全性.

    时间复杂度o(8*log2n*28*n)

    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define MAXN 1001
    using namespace std;
    int f[MAXN][(1<<8)+10];
    int n,a[MAXN],full=(1<<8)-1;
    bool had[10];
    vector<int>pos[10];
    inline void pre()
    {
       scanf("%d",&n);
       for(int i=1;i<=n;i++)
       {
        scanf("%d",&a[i]);
        had[a[i]]=1;
        pos[a[i]].push_back(i);
       }
    }
    inline int Max(int x,int y)
    {
       return x>y?x:y;
    }
    inline int get(int p,int len)
    {
       int now=lower_bound(pos[a[p]].begin(),pos[a[p]].end(),p)-pos[a[p]].begin();
       int ans=now+len-1;
       if(pos[a[p]].size()-1<ans)return -1;
       return pos[a[p]][ans];
    }
    int judge(int len)
    {
       memset(f,0,sizeof(f));
       for(int i=0;i<n;i++)
       {
          int to=get(i+1,len);
          if(to!=-1)f[to][(1<<(a[i+1]-1))]=Max(f[i][0]+len,f[to][(1<<(a[i+1]-1))]);
          to=get(i+1,len+1);
          if(to!=-1)f[to][(1<<(a[i+1]-1))]=Max(f[i][0]+len+1,f[to][(1<<(a[i+1]-1))]);
          for(int j=1;j<full;j++)
            if(f[i][j])
            {
              f[i+1][j]=Max(f[i+1][j],f[i][j]);
              if(j&(1<<(a[i+1]-1)))continue;
              to=get(i+1,len);
              if(to!=-1)f[to][j|(1<<(a[i+1]-1))]=Max(f[i][j]+len,f[to][j|(1<<(a[i+1]-1))]);
              to=get(i+1,len+1);
              if(to!=-1)f[to][j|(1<<(a[i+1]-1))]=Max(f[i][j]+len+1,f[to][j|(1<<(a[i+1]-1))]);
            }
         f[i+1][full]=Max(f[i+1][full],f[i][full]);
        }
       return f[n][full];
    }
    void work()
    {
       int ans=0,l=1,r=n>>3;
       for(int i=1;i<=8;i++)
        if(had[i])ans++;
       while(l<=r)
       {
         int mid=(l+r)>>1,x=judge(mid);
         ans=Max(x,ans);
         if(x)
          l=mid+1;
         else
          r=mid-1;
       }
       printf("%d",ans);
    }
    int main()
    {
       pre();
       work();
       return 0;
    }
  • 相关阅读:
    markdown自动生成侧边栏TOC /目录
    jquery和javascript的区别
    Jquery中AJAX参数详细(1)-转
    jQuery.ajax介绍
    人人开源分模块,非原生html报错,很难查找问题所在,有vue语法
    《SSH网上商城》-视频目录--代码可以跑起来
    《第16项目:国家税务协同平台项目》-视频目录
    项目:《ssh框架综合项目开发视频》-视频目录和第六天的EasyUI简单讲解
    项目:《JavaWeb图书管理系统视频》--代码修复还可以运行起来
    Maven项目在更新过程停止,再更新无效-->解决
  • 原文地址:https://www.cnblogs.com/TSHugh/p/7106544.html
Copyright © 2020-2023  润新知