标签:依次 需要 c++ 转移 现在 while 简单 用户 一个
可能最近做二分和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[i]$表示权值等于i时的最大答案值,最后再扫一遍就好了。
END
标签:依次 需要 c++ 转移 现在 while 简单 用户 一个
原文地址:https://www.cnblogs.com/antiquality/p/9033693.html