1. 程式人生 > >hdu5693 D Game

hdu5693 D Game

review panel play get ace 字符 tom 數據 input

鏈接

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 2016"百度之星" - 初賽(Astar Round2A)

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