D Game
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 883 Accepted Submission(s): 317
Problem Description
众所周知,度度熊喜欢的字符只有两个:B 和D。
今天,它发明了一个游戏:D游戏。
度度熊的英文并不是很高明,所以这里的D,没什么高深的含义,只是代指等差数列[(等差数列百科)](http://baike.baidu.com/view/62268.htm)中的公差D。
这个游戏是这样的,首先度度熊拥有一个公差集合{D},然后它依次写下N个数字排成一行。游戏规则很简单:
1. 在当前剩下的有序数组中选择X(X≥2) 个连续数字;
2. 检查1选择的X个数字是否构成等差数列,且公差 d∈{D};
3. 如果2满足,可以在数组中删除这X个数字;
4. 重复 1−3 步,直到无法删除更多数字。
度度熊最多能删掉多少个数字,如果它足够聪明的话?
今天,它发明了一个游戏:D游戏。
度度熊的英文并不是很高明,所以这里的D,没什么高深的含义,只是代指等差数列[(等差数列百科)](http://baike.baidu.com/view/62268.htm)中的公差D。
这个游戏是这样的,首先度度熊拥有一个公差集合{D},然后它依次写下N个数字排成一行。游戏规则很简单:
1. 在当前剩下的有序数组中选择X(X≥2) 个连续数字;
2. 检查1选择的X个数字是否构成等差数列,且公差 d∈{D};
3. 如果2满足,可以在数组中删除这X个数字;
4. 重复 1−3 步,直到无法删除更多数字。
度度熊最多能删掉多少个数字,如果它足够聪明的话?
Input
第一行一个整数T,表示T(1≤T≤100) 组数据。
每组数据以两个整数 N,M 开始 。接着的一行包括 N 个整数,表示排成一行的有序数组 Ai。接下来的一行是 M 个整数,即给定的公差集合 Di。
1≤N,M≤300
−1 000 000 000≤Ai,Di≤1 000 000 000
每组数据以两个整数 N,M 开始 。接着的一行包括 N 个整数,表示排成一行的有序数组 Ai。接下来的一行是 M 个整数,即给定的公差集合 Di。
1≤N,M≤300
−1 000 000 000≤Ai,Di≤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
Source
Recommend
wange2014
这个问题可以看出是dp,但如果用f[i][j]表示i到j能删除多少个似乎并不好转移,我们可以转变一下思路,f[i][j]表示i到j能否全部删除,假如我们求出了这个,我们可以通过一个简单的dp得到所有数一共最多删多少个。
因为要连续删除x>=2个数字,事实上,删4个和分两次删,各删2个,删5个分两次,分别删2,3个是一样的,2和3可以凑出所有的数字,于是我们只需要考虑通过删2个或者3个来转移即可。
我们将问题分为两种情况,最后一次删除是否同时删除了左右端点,如果不是,那么我们一定可以将原区间分为两段,把问题分为两个更小的子问题,通过区间dp解决,如果是,那么我们要分为两种情况,删2个或者删3个,如果删两个,那么我们是可以通过f[i+1][j-1]转移而来,如果删了3个,那么我们再次枚举第三个是哪里,即将问题转换为了两个子问题f[i+1][k-1],f[k+1][j-1],区间dp即可求出f数组。
1 #include<cstdio> 2 #include<cstring> 3 #define ll long long 4 #define max(a,b) a>b?a:b 5 using namespace std; 6 const int inf=1e9+1; 7 const int Hash1=1e5+7; 8 const int Hash2=1e5+9; 9 int T,n,m,a[301],dp[301]; 10 bool hs1[100010],hs2[100010]; 11 bool f[301][301]; 12 bool check(int x){ 13 return hs1[((ll)x+inf)%Hash1]&&hs2[((ll)x+inf)%Hash2]; 14 } 15 struct seg{ 16 int l,r; 17 seg(){} 18 seg(int x,int y){ 19 l=x;r=y; 20 } 21 }s[90001]; 22 int cnt; 23 int main() 24 { 25 // freopen("1.txt","r",stdin); 26 scanf("%d",&T); 27 while(T--){ 28 scanf("%d%d",&n,&m); 29 memset(f,0,sizeof(f)); 30 memset(hs1,0,sizeof(hs1)); 31 memset(hs2,0,sizeof(hs2)); 32 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 33 for(int i=1;i<=n;i++) 34 for(int j=1;j<i;j++) 35 f[i][j]=1; 36 for(int i=1;i<=m;i++){ 37 int x; 38 scanf("%d",&x); 39 hs1[(x+inf)%Hash1]=1; 40 hs2[(x+inf)%Hash2]=1; 41 } 42 for(int l=2;l<=n;l++){ 43 for(int i=1;i+l-1<=n;i++){ 44 int j=i+l-1; 45 for(int k=i;k<=j-1;k++){ 46 if(f[i][k]&f[k+1][j])f[i][j]=1; 47 } 48 if(check(a[j]-a[i])&&f[i+1][j-1])f[i][j]=1; 49 for(int k=i+1;k<=j-1;k++){ 50 if(a[k]-a[i]==a[j]-a[k]&&check(a[k]-a[i])){ 51 if(f[i+1][k-1]&&f[k+1][j-1])f[i][j]=1; 52 } 53 } 54 } 55 } 56 cnt=0; 57 for(int i=1;i<n;i++) 58 for(int j=i+1;j<=n;j++) 59 if(f[i][j])s[++cnt]=seg(i,j); 60 memset(dp,0,sizeof(dp)); 61 int now=1; 62 for(int i=1;i<=n;i++){ 63 dp[i]=max(dp[i],dp[i-1]); 64 while(s[now].l==i&&now<=cnt){ 65 dp[s[now].r]=max(dp[s[now].r],dp[i-1]+s[now].r-s[now].l+1); 66 now++; 67 } 68 } 69 printf("%d\n",dp[n]); 70 } 71 return 0; 72 }