codeforces 505C Mr. Kitayuta, the Treasure Hunter(dp)

题目链接

C. Mr. Kitayuta, the Treasure Hunter
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

The Shuseki Islands are an archipelago of 30001 small islands in the Yutampo Sea. The islands are evenly spaced along a line, numbered from 0 to 30000 from the west to the east. These islands are known to contain many treasures. There are n gems in the Shuseki Islands in total, and the i-th gem is located on island pi.

Mr. Kitayuta has just arrived at island 0. With his great jumping ability, he will repeatedly perform jumps between islands to the east according to the following process:

  • First, he will jump from island 0 to island d.
  • After that, he will continue jumping according to the following rule. Let l be the length of the previous jump, that is, if his previous jump was from island prev to island cur, let l = cur - prev. He will perform a jump of length l - 1l or l + 1 to the east. That is, he will jump to island (cur + l - 1)(cur + l) or (cur + l + 1) (if they exist). The length of a jump must be positive, that is, he cannot perform a jump of length 0 when l = 1. If there is no valid destination, he will stop jumping.

Mr. Kitayuta will collect the gems on the islands visited during the process. Find the maximum number of gems that he can collect.

Input

The first line of the input contains two space-separated integers n and d (1 ≤ n, d ≤ 30000), denoting the number of the gems in the Shuseki Islands and the length of the Mr. Kitayuta's first jump, respectively.

The next n lines describe the location of the gems. The i-th of them (1 ≤ i ≤ n) contains a integer pi (d ≤ p1 ≤ p2 ≤ ... ≤ pn ≤ 30000), denoting the number of the island that contains the i-th gem.

Output

Print the maximum number of gems that Mr. Kitayuta can collect.

Sample test(s)
input
4 10
10
21
27
27
output
3
input
8 8
9
19
28
36
45
55
66
78
output
6
input
13 7
8
8
9
16
17
17
18
21
23
24
24
26
30
output
4

题意:有30001个岛,在一条线上,从左到右编号一次为0到30000。某些岛屿上有些宝石。初始的时候有个人在岛屿0,他将跳到岛屿d,他跳跃的距离为d。如果当前他跳跃的距离为L,他下一次跳跃的距离只能为L-1,L,L+1之一且不能为0。他只能往编号更大的岛跳,直到他不能跳,问他最多能收集多少个宝石?

题解:很容易想到dp,用dp[i][j] 表示当前在岛屿i,上一次跳跃的距离为j,最多能收集多少个宝石。但是这样无论空间还是时间都不能接受。我们可以发现,他跳跃的距离L不会超过d+250,因为1+2+3+...250>30000。有了这个性质,我们就可以用dp[i][j]表示当前在岛屿i,上一次跳跃的距离为d+j,该状态下他最多能收集多少个宝石?

空间复杂度和时间复杂度都为O(n*sqrt(n))。

代码如下:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<stdlib.h>
#include<vector>
#define inff 0x3fffffff
#define nn 110000
#define mod 1000000007
typedef long long LL;
const LL inf64=inff*(LL)inff;
using namespace std;
int n,d;
int num[31000];
int dp[31000][510];
int main()
{
    int i,x,j;
    while(scanf("%d%d",&n,&d)!=EOF)
    {
        memset(num,0,sizeof(num));
        for(i=1;i<=n;i++)
        {
            scanf("%d",&x);
            num[x]++;
        }
        memset(dp,-1,sizeof(dp));
        dp[d][250]=num[d];
        int ans=0;
        for(i=d;i<=30000;i++)
        {
            for(j=0;j<=500;j++)
            {
                if(dp[i][j]!=-1)
                {
                    ans=max(dp[i][j],ans);
                    if(i+d+j-250<=30000)
                        dp[i+d+j-250][j]=max(dp[i+d+j-250][j],dp[i][j]+num[i+d+j-250]);
                    if(i+d+j-1-250<=30000&&d+j-250-1)
                        dp[i+d+j-251][j-1]=max(dp[i+d+j-251][j-1],dp[i][j]+num[i+d+j-251]);
                    if(i+d+j+1-250<=30000)
                        dp[i+d+j+1-250][j+1]=max(dp[i+d+j+1-250][j+1],dp[i][j]+num[i+d+j+1-250]);
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
比赛的时候我没有想到正解,但是知道有效状态数不会太多,所以使用记忆化搜索写过的,当然还要到hash。

复杂度为O(10^7),代码如下:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<stdlib.h>
#include<vector>
#define inff 0x3fffffff
#define nn 21000
#define mod 20000009
typedef long long LL;
const LL inf64=inff*(LL)inff;
using namespace std;
int n,d;
int num[3*nn];
int sum[3*nn];
int mxid;
int ha[nn*1000];
int hashx(int x,int y)
{
    int ix=x+30007*y;
    int key=ix%mod;
    int i;
    for(i=key;;i=(i+1)%mod)
    {
        if(ha[i]==-1)
        {
            ha[i]=ix;
            break;
        }
        else if(ha[i]==ix)
            break;
    }
    return i;
}
int dp[nn*1000];
int dfs(int id,int l)
{
    if(l==1||l==2)
        return sum[mxid]-sum[id-1];
    int ix=hashx(id,l);
    if(dp[ix]!=-1)
        return dp[ix];
    int re=0;
    if(id+l<=mxid)
        re=max(re,dfs(id+l,l));
    if(id+l-1<=mxid&&l-1>0)
        re=max(re,dfs(id+l-1,l-1));
    if(id+l+1<=mxid)
        re=max(re,dfs(id+l+1,l+1));
    return dp[ix]=re+num[id];
}
int main()
{
    int i,x;
    while(scanf("%d%d",&n,&d)!=EOF)
    {
        memset(num,0,sizeof(num));
        memset(ha,-1,sizeof(ha));
        memset(dp,-1,sizeof(dp));
        sum[0]=0;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&x);
            num[x]++;
            mxid=x;
        }
        for(i=1;i<=mxid;i++)
        {
            sum[i]=sum[i-1]+num[i];
        }
        if(d==1||d==2)
            printf("%d\n",n);
        else
            printf("%d\n",dfs(d,d));
    }
    return 0;
}



你可能感兴趣的:(dp,ACM,codeforces)