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;
}





原文地址:https://www.cnblogs.com/JYYHH/p/8397905.html