• HDOJ 5693 D Game


    众所周知,度度熊喜欢的字符只有两个:B 和D。 

    今天,它发明了一个游戏:D游戏。 

    度度熊的英文并不是很高明,所以这里的D,没什么高深的含义,只是代指等差数列[(等差数列百科)](http://baike.baidu.com/view/62268.htm)中的公差D。 

    这个游戏是这样的,首先度度熊拥有一个公差集合${D}$,然后它依次写下$N$个数字排成一行。游戏规则很简单: 

    1. 在当前剩下的有序数组中选择$X (X geq 2)$ 个连续数字; 

    2. 检查$1$选择的$X$个数字是否构成等差数列,且公差 $din {D}$; 

    3. 如果$2$满足,可以在数组中删除这$X$个数字; 

    4. 重复 $1 - 3$ 步,直到无法删除更多数字。 

    度度熊最多能删掉多少个数字,如果它足够聪明的话? 

    Input

    第一行一个整数$T$,表示$T(1 leq T leq 100)$ 组数据。 

    每组数据以两个整数 $N$,$M$ 开始 。接着的一行包括 $N$ 个整数,表示排成一行的有序数组 $A_{i}$。接下来的一行是 $M$ 个整数,即给定的公差集合 $D_{i}$。 

    $1 leq N, M leq 300$ 

    $-1 000 000 000 leq A_{i}, D_{i} leq 1 000 000 000$ 
    Output

    对于每组数据,输出最多能删掉的数字 。

    Sample Input

    3
    3 1
    1 2 3
    1
    3 2
    1 2 4
    1 2
    4 2
    1 3 4 3
    1 2

    Sample Output

    3
    2
    4


    首先发现如果每次只删两个或者三个的话是肯定可以得到最优解的,因为任意长度的等差数列都可以由2和3组合出来。。短的反而好找。
    而且它要求必须是删连续的数,这就类似于括号匹配,对于[A],只有A合法了[A]才合法。只不过还需要多考虑一种<|>构成的长度为三的括号。

    可以先预处理出那些段可以删,然后最后dp用f[i]表示前i个数最多可以删多少转移即可。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<map>
    #define ll long long
    #define maxn 305
    using namespace std;
    map<int,int> mmp;
    bool can[maxn][maxn];
    int f[maxn],n,m,T;
    int ans,a[maxn],now;
    
    inline void pre(){
        for(int i=2;i<=n;i++) if(mmp.count(a[i]-a[i-1])) can[i-1][i]=1;
        for(int i=3;i<=n;i++) if((a[i-1]<<1)==a[i]+a[i-2])
            if(mmp.count(a[i]-a[i-1])) can[i-2][i]=1;
        
        for(int len=4;len<=n;len++)
            for(int i=len,j=1;i<=n;i++,j++){
                int tt=a[i]+a[j];
                bool flag=!(tt&1);
                tt>>=1;
                if(flag&&!mmp.count((a[i]-a[j])>>1)) flag=0;
                
                if(mmp.count(a[i]-a[j])&&can[j+1][i-1]){
                    can[j][i]=1;
                    continue;
                }
                
                for(int k=j+1;k<i;k++){
                    if(can[j][k]&&can[k+1][i]){
                        can[j][i]=1;
                        break;
                    }
                    if(flag&&a[k]==tt&&can[j+1][k-1]&&can[k+1][i-1]){
                        can[j][i]=1;
                        break;
                    }
                }
            }
    }
    
    inline void dp(){
        for(int i=1;i<=n;i++){
            f[i]=f[i-1];
            for(int j=i-1;j;j--) if(can[j][i]) f[i]=max(f[i],f[j-1]+i-j+1);
        }
        ans=f[n];
    }
    
    int main(){
        scanf("%d",&T);
        while(T--){
            memset(can,0,sizeof(can));
            memset(f,0,sizeof(f));
            mmp.clear(),ans=0;
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++) scanf("%d",a+i);
            for(int i=1;i<=m;i++) scanf("%d",&now),mmp[now]=1;
            
            pre();
            dp();
            
            printf("%d
    ",ans);
        }
        
        return 0;
    }
    
    
    



  • 相关阅读:
    导入导出通用库
    镜像下载地址
    后端请求接口的几种方式
    获取本机的mac地址
    Arduino串口的一些高级用法
    手机与Arduino蓝牙串口通讯实验及完整例程
    ARDUINO+MCP2515实现CAN通讯接收
    Arduino IIC 主从设备连接通信
    上位机与单片机的通信问题
    NRF24L01多对一、多通道通讯关键代码
  • 原文地址:https://www.cnblogs.com/JYYHH/p/8397905.html
Copyright © 2020-2023  润新知