hdu5693(区间dp)D Game

来源:互联网 发布:java api中文版 编辑:程序博客网 时间:2024/06/05 02:34


D Game

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 703    Accepted Submission(s): 257


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

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

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

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

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

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

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

4. 重复 13 步,直到无法删除更多数字。

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

Input
第一行一个整数T,表示T(1T100) 组数据。

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

1N,M300

1 000 000 000Ai,Di1 000 000 000
 

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

Sample Input
33 11 2 313 21 2 41 24 21 3 4 31 2
 

Sample Output
324
 

Source
2016"百度之星" - 初赛(Astar Round2A)

如果一次操作中,我们删除了>=4个数,我们必然可以把这次操作分成多次,每次只删除2或3个数。

于是,就可以dp了。

dp[i][i]=0,dp[i][i-1]=1
如果满足以下情况之一,则dp[i][j]=1,否则dp[i][j]=0
dp[i][k]&&dp[k+1][j]    i<k<j
若删除的等差数列为2项
dp[i+1][j-1]&&(d==a[j]-a[i])
若删除的等差数列为3项
a[j]-a[k]==a[k]-a[i]==d && dp[i+1][k-1] && dp[k+1][j-1]
其中,d为某个公差,可通过set快速查找


#include<cstdio>#include<iostream>#include<set>#include<cstring>using namespace std;const int mn=305;int n,m,a[mn],dp[mn];bool f[mn][mn];int main(){int T;scanf("%d",&T);while(T--){scanf("%d%d",&n,&m);memset(f,0,sizeof(f));memset(dp,0,sizeof(dp));for(int i=1;i<=n;++i)scanf("%d",a+i),f[i][i-1]=true;//这个初始化主要是两个挨着的删除时的情况 set<int> st;while(m--){int t;scanf("%d",&t);st.insert(t);}for(int len=1;len<n;++len)for(int i=1;i+len<=n;++i){int j=i+len;//两个删除 if(f[i+1][j-1]&&st.count(a[j]-a[i])) f[i][j]=true;//三个删除或者已全部删除if(!f[i][j])for(int k=i+1;k<j;++k)if(f[i][k]&&f[k+1][j]||f[i+1][k-1]&&f[k+1][j-1]&&a[k]-a[i]==a[j]-a[k]&&st.count(a[k]-a[i])){f[i][j]=true;break;}}//到了这里,其实可以排序贪心来做,但是dp看起来简洁 for(int i=1;i<=n;++i){for(int j=1;j<i;++j)if(f[j][i]) dp[i]=max(dp[i],dp[j-1]+i-j+1);dp[i]=max(dp[i],dp[i-1]);}printf("%d\n",dp[n]);}return 0; }