hdu 5693 D Game

D Game

 HDU - 5693 

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

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

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

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

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

2. 检查$1$选择的$X$个数字是否构成等差数列,且公差 $d\in \{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
/*
    每删除一段区间,假设区间长度为len,那么len一定能表示成2*i+3*j的形式,也就是每次可以只删除长度为2或3的长度即可
    过程分两步: 
    1.先处理出f[i][j]=1/0,代表区间[i,j]能否全部删除,首先枚举一个中间点k,能由三种情况转移过来:
        ①如果[i,k]和[k+1,j]能被删除,那么[l,r]一定能被删除 
        ②如果[i+1,k]和[k+1,r-1]能被删除并且a[i]和a[j]能被删除,那么[l,r]一定能被删除 
        ③如果[i+1,k-1]和[k+1,r-1]能被删除并且a[i],a[k],a[j]能被删除,那么[l,r]一定能被删除
    2.dp[i]表示到第i位最多能删除的数字个数,用f[][]转移即可 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#define maxn 310
using namespace std;
int n,m,T,a[maxn],dp[maxn];
bool f[maxn][maxn];
map<int,int>mark;
void work1(){
    for(int i=2;i<=n;i++)if(mark[a[i]-a[i-1]])f[i-1][i]=1;
    for(int i=3;i<=n;i++)if(a[i-1]-a[i-2]==a[i]-a[i-1]&&mark[a[i]-a[i-1]])f[i-2][i]=1;
    for(int len=4;len<=n;len++)
        for(int i=1;i+len-1<=n;i++){
            int j=i+len-1;
            for(int k=i+1;k<j;k++)f[i][j]|=(f[i][k]&f[k+1][j]);
            if(mark[a[j]-a[i]])f[i][j]|=f[i+1][j-1];
            for(int k=i+1;k<j;k++)
                if(a[j]-a[k]==a[k]-a[i]&&mark[a[k]-a[i]])
                f[i][j]|=f[i+1][k-1]&f[k+1][j-1];
        }
}
void work2(){
    for(int i=1;i<=n;i++){
        dp[i]=dp[i-1];
        for(int j=1;j<=i;j++){
            if(!f[j][i])continue;
            dp[i]=max(dp[i],dp[j-1]+i-j+1);
        }
    }
}
int main(){
    freopen("Cola.txt","r",stdin);
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        mark.clear();
        memset(f,0,sizeof(f));
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        int x;
        for(int i=1;i<=m;i++){
            scanf("%d",&x);
            mark[x]=1;
        }
        work1();
        work2();
        printf("%d\n",dp[n]);
    }
}

 

posted @ 2018-01-17 18:12  Echo宝贝儿  阅读(242)  评论(0编辑  收藏  举报