hdu5693 D Game

Posted turkeyghb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu5693 D Game相关的知识,希望对你有一定的参考价值。

链接

 

 

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(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
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 }
View Code

 

以上是关于hdu5693 D Game的主要内容,如果未能解决你的问题,请参考以下文章

hdu5693 D Game

HDU5693

hdu 5693

hdu 5693 朋友 博弈

HDU 4642 Fliping game

HDU 1528 Card Game Cheater