【dp】淘宝的推荐系统

可能最近做二分和DFS做傻了?

小明刚刚入职淘宝,老大给他交代了一个简单的任务,实现一个简易的商品推荐系统。

这个商品推荐系统的需求如下:

一共有 n 件商品可以被推荐,他们的编号分别为 1 到 n。每件商品都有一个价格,编号为 i 的商品价格为 pi​ 元。现在需要给用户推荐尽可能多的商品,但是要保证按照编号上升的顺序给用户依次推荐商品,并且,相邻商品的价格之差的绝对值不能超过 d。注意,第一个推荐的商品价格没有限制。

输入格式

第一行输入一个整数 T,表示测试数据组数。

接下来依次输入 T 组数据,每组数据按照下面的格式输入:

第一行输入两个整数 n 和 d,意义如题目描述所示。

接下来一行输入 n 个整数,第 i 个整数表示 pi​。

保证 $1<T≤50$, $1≤n≤30000$, $0≤d≤100$, $1≤pi​≤10^5$。

保证 $∑n≤6∗10^5$。

输出格式

对于每组数据,输出一行一个整数,表示最多能推荐的商品个数。

 


 

题目分析

诶,思路大概被最近做的题目带的有点偏……

看到的第一眼是二分,然后果断叉掉了……

然后就开始想带记忆化的DFS,不过捣鼓了半天发现是会TLE的……

赛时dp一直没怎么理解,直到赛后才意识到好水好水的dp题目啊……

大概是dp姿势不太好吧……

这个是带记忆化的DFS:

 1 #include<bits/stdc++.h>
 2 const int maxn = 50003;
 3 
 4 int tt,n,m,ans;
 5 int a[maxn],anss[maxn];
 6 bool vis[maxn];
 7 
 8 int dfs(int now)
 9 {
10     if (vis[now]) return anss[now];
11     int tt = now, cnt = 0;
12     for (;;)
13     {
14         tt++;
15         while (abs(a[tt]-a[now])>m) tt++;
16         if (tt <= n) cnt = std::max(dfs(tt), cnt);
17         else break;
18     }
19     vis[now] = 1;
20     return anss[now]=cnt+1;
21 }
22 int main()
23 {
24     scanf("%d",&tt);
25     while (tt--)
26     {
27         ans = 1;
28         scanf("%d%d",&n,&m);
29         memset(vis, 0, sizeof vis);
30         memset(anss, 0, sizeof anss);
31         for (int i=1; i<=n; i++) scanf("%d",&a[i]),anss[i] = 1;
32         for (int i=1; i<=n; i++)
33             if (!vis[i])
34                 ans = std::max(ans, dfs(i));
35         printf("%d\n",ans);
36     }
37     return 0;
38 }

这个是dp:

 1 #include<bits/stdc++.h>
 2 const int maxn = 100003;
 3 
 4 int tt,x,n,m,ans;
 5 int f[maxn];
 6 
 7 int main()
 8 {
 9     scanf("%d",&tt);
10     while (tt--)
11     {
12         ans = 0;
13         scanf("%d%d",&n,&m);
14         memset(f, 0, sizeof f);
15         for (int i=1; i<=n; i++)
16         {
17             scanf("%d",&x);
18             int w = f[x]+1;
19             for (int j=std::max(1, x-m); j<=std::min(maxn-1, x+m); j++)   //不要局限于数据形式,把dp对象转移成权值
20                 f[j] = std::max(f[j], w);
21         }
22         for (int i=1; i<maxn; i++)
23             ans = std::max(ans, f[i]);
24         printf("%d\n",ans);
25     }
26     return 0;
27 }

其中注意到权值较小,我们用$f[j]$表示权值等于$j$时的最大答案值,最后再扫一遍就好了。

关键在于这里的输入天然有序,因此$f[j]$表示$1~i-1$之中权值为$j$的答案数,也就是说这里是把n维的dp优化到了1维

 

 

 

 

END

posted @ 2018-05-13 22:17  AntiQuality  阅读(1323)  评论(0编辑  收藏  举报