• 2019 TCO Round 1B——[ 状压DP ]


    第一题是 EllysSki 。

    题意:给n个数,求两个方向的最长递减区间。

    可以O(n)。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    int Mx(int a,int b){return a>b?a:b;}
    
    class EllysSki{
    public:
      int getMax(vector <int> height);
    };
    
    int EllysSki::getMax(vector <int> height)
    {
      int n=height.size(),ans=0;
      for(int i=0;i<n;i++)
        {
          int j=i;
          while(j+1<n&&height[j+1]<=height[j])
        j++;
          ans=Mx(ans,j-i+1); i=j;
        }
      for(int i=n-1;i>=0;i--)
        {
          int j=i;
          while(j&&height[j-1]<=height[j])
        j--;
          ans=Mx(ans,i-j+1); i=j;
        }
      return ans;
    }
    View Code

    第二题是 EllysTeleport 。

    题意:连边,找最长链。

    自己写了tarjan,没调出来。其实 n2 暴力也行。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    int Mx(int a,int b){return a>b?a:b;}
    int Mn(int a,int b){return a<b?a:b;}
    const int N=1e4+5;
    int n,h[N],to[N]; bool vis[N];
    class EllysTeleport{
      int fnd(int x)
      {
        int l=1,r=n,ret=0;
        while(l<=r)
          {
        int mid=l+r>>1;
        if(h[mid]<=x)ret=mid,l=mid+1;
        else r=mid-1;
          }
        return ret;
      }
    public:
      int getMax(int N, int H1, int A, int B, int P, int Q, int M)
      {
        n=N; h[1]=H1;
        for(int i=2;i<=n;i++)
          h[i]=((ll)h[i-1]*A+B)%M;
        sort(h+1,h+n+1);
        for(int i=1;i<=n;i++)
          {
        int d=((ll)h[i]*P+Q)%M;
        to[i]=fnd(d);
          }
        int ans=0;
        for(int i=1;i<=n;i++)
          {
        memset(vis,0,sizeof vis);
        int cnt=1,cr=to[i]; vis[i]=1;
        while(cr&&!vis[cr])
          {
            cnt++;vis[cr]=1;cr=to[cr];
          }
        ans=Mx(ans,cnt);
          }
        return ans;
      }
    };
    View Code

    第三题是 EllysPearls 。

    题意:n(<=50) 个球排成一排,每个球是 m(<=15) 种颜色之一。一次操作可以拿出序列中任意一个球,再插进序列的任意一个位置。求最少操作次数使得相同颜色的球是一个区间。

    题解:https://www.topcoder.com/blog/2019-topcoder-open-algorithm-round-1b-editorials/

    颜色只有 15 ,考虑状压。 1 表示该颜色之前已经确定了一个位置,即当前球必须取出、融入之前自己颜色的区间。

    特殊情况就是当前球不动,就能合法;所以再记目前最后的颜色是什么(可以是空)。

    还可能遇到当前球,但是把它放在后面,即尚不确定当前颜色。发现这种情况和“融入之前自己颜色的区间”都是要花费1的代价,并且不改变状压的状态。

    所以 dp[ i ][ j ][ s ] 表示前 i 个、末尾颜色是 j 、已经确定位置的颜色集合是 s ,即可转移。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    const int N=55,K=20,M=(1<<15)+5;
    int n,m,a[N],bin[K],dp[2][K][M];
    class EllysPearls{
      void cz(int &x,int y){if(y<x)x=y;}
    public:
      int getMin(int tN, int tM, vector <int> pearls)
      {
        n=tN; m=tM; for(int i=0;i<n;i++)a[i+1]=pearls[i];
        bin[0]=1;for(int i=1;i<=m;i++)bin[i]=bin[i-1]<<1;
        memset(dp[1],0x3f,sizeof dp[1]);
        dp[1][0][0]=0; bool u=1,v=0;
        for(int i=1;i<=n;i++,swap(u,v))
          {
        memset(dp[v],0x3f,sizeof dp[v]);
        for(int j=0;j<=m;j++)
          for(int s=0;s<bin[m];s++)//[m]not[n]
            {
              int tp=dp[u][j][s]; if(tp>N)continue;
              int d=bin[a[i]-1];
              cz(dp[v][j][s],tp+1);
              if(!j||j==a[i])
            cz(dp[v][a[i]][s|d],tp);
              if(!(s&d))
            cz(dp[v][a[i]][s|d],tp);
            }
          }
        int ans=N;
        for(int j=0;j<=m;j++)
          for(int s=0;s<bin[m];s++)
        cz(ans,dp[u][j][s]);
        return ans;
      }
    };
    View Code
  • 相关阅读:
    js中return 、return false 、return true、break、continue区别
    小程序mpvue下多层次的数据值改变但是页面不动态渲染
    Thinkpad T470p Clover and opencore 吃黑苹果 Catalina 10.15.5
    3dTiles 数据规范详解[4.5] *一个被废弃的非正式瓦片规范
    3dTiles 数据规范详解[4.4] cmpt瓦片二进制数据文件结构
    3dTiles 数据规范详解[4.3] pnts瓦片二进制数据文件结构
    3dTiles 数据规范详解[4.2] i3dm瓦片二进制数据文件结构
    记一次Windows MinGW g++编译c++代码
    3dTiles 数据规范详解[4.1] b3dm瓦片二进制数据文件结构
    3dTiles 数据规范详解[3] 内嵌在瓦片文件中的两大数据表
  • 原文地址:https://www.cnblogs.com/Narh/p/10801431.html
Copyright © 2020-2023  润新知