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$个数字是否构成等差数列,且公差 $d\in \{D\}$;
3. 如果$2$满足,可以在数组中删除这$X$个数字;
4. 重复 $1 - 3$ 步,直到无法删除更多数字。
度度熊最多能删掉多少个数字,如果它足够聪明的话?
今天,它发明了一个游戏: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
首先发现如果每次只删两个或者三个的话是肯定可以得到最优解的,因为任意长度的等差数列都可以由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\n",ans); } return 0; }
我爱学习,学习使我快乐