在不使用图表的情况下以最小产品从第一个索引到最后一个索引?

Posted

技术标签:

【中文标题】在不使用图表的情况下以最小产品从第一个索引到最后一个索引?【英文标题】:Reaching from first index to last with minimum product without using Graphs? 【发布时间】:2015-10-24 04:45:24 【问题描述】:

在 codechef 上解决这个problem:

在拜访了一个儿时的朋友之后,厨师想回到他的家。 朋友住第一街,大厨自己住N街 (也是最后一条)街道。他们的城市有点特别:你可以从 第 X 街到第 Y 街当且仅当 1

输入的第一行包含两个整数 - N 和 K - 分别为街道数量和 K 值。第二行 由 N 个数字组成 - 分别为 A1、A2、...、AN,其中 Ai 等于 到第 i 条街道的特殊号码。输出

请输出最小可能乘积的值,取模 1000000007. 约束

1 ≤ N ≤ 10^5 1 ≤ Ai ≤ 10^5 1 ≤ K ≤ N 示例

输入:4 2 1 2 3 4。

输出:8

可以使用基于tutorial 的 graphs 来解决 我试图在不使用图表的情况下仅使用 recursionDP 来解决它。 我的做法:

    获取一个数组并计算到达每个索引的最小乘积并将其存储在相应的索引中。 这可以使用自上而下的方法和递归发送索引(符合条件)直到达到起始索引来计算。 在所有计算值中存储最小值。 如果已经计算,则返回,否则计算。

代码:

 #include<iostream>
 #include<cstdio>
 #define LI long int
 #define MAX 100009
 #define MOD 1000000007
 using namespace std;
 LI dp[MAX]=0;
 LI ar[MAX],k,orig;
 void cal(LI n)
 
       if(n==0)
          return;
       if(dp[n]!=0)
          return;
       LI minn=MAX;
       for(LI i=n-1;i>=0;i--)
       
          if(ar[n]-ar[i]<=k && ar[n]-ar[i]>=1)
          
              cal(i);
              minn=(min(dp[i]*ar[n],minn))%MOD;
          
       
       dp[n]=minn%MOD;
       return;
 

 int main()
 
    LI n,i;
    scanf("%ld %ld",&n,&k);
    orig=n;
    for(i=0;i<n;i++)
       scanf("%ld",&ar[i]);
    dp[0]=ar[0];
    cal(n-1);
    if(dp[n-1]==MAX)
       printf("0");
    else printf("%ld",dp[n-1]);
    return 0;

已经 2 天了,我已经检查了每一个角落案例和限制,但它仍然给出了错误的答案!解决方案有什么问题?

需要帮助。

【问题讨论】:

为什么我添加问题陈述引用:链接可能会及时过时,这里的帖子应该是从现在开始的相关年份;当您可以将所有信息集中在一个地方时,为什么要让我们点击链接以获取基本信息,这里。为什么我没有删除链接(因为我把所有信息都带到了这里):attribution. 我更新了我的答案,并解决了所有问题。您的 DP 方法成本太高,通过使用自下而上的 dp,您可以达到正确的复杂性以通过所有测试用例。 【参考方案1】:

分析

有很多问题。这是我发现的:

    您无故将产品限制为低于100009 的值。产品可以比那个高得多(这确实是问题只要求取模1000000007的原因) 您限制您从special number 差异为K 的街道移动,而问题陈述说您可以在index 差异低于K 的任何城市之间移动 在动态规划函数中,您计算​​产品并存储产品的模数。这可能会导致问题,因为大数的模数可能低于较小数的模数。这可能会破坏以后的计算。 您使用的整数类型long int 太短了。 您的算法复杂度太高。

在所有这些问题中,最后一个是最严重的。我通过改变整个方法并使用更好的数据结构来修复它。

第一个问题

在您的main() 函数中:

if(dp[n-1]==MAX)
   printf("0");

在您的cal() 函数中:

LI minn=MAX;

您应该将此行替换为:

LI minn = std::numeric_limits<LI>::max();

别忘了:

#include <limits>

第二个问题

   for(LI i=n-1;i>=0;i--)
   
      if(ar[n]-ar[i]<=k && ar[n]-ar[i]>=1)
      
          . . .
      
   

你应该替换for循环条件:

  for(LI i=n-1;i>=n-k;i--)

并完全删除特殊数字的条件。

第三个问题

您正在寻找特殊数字乘积最小的路径。在您当前的设置中,您取产品的模之后比较路径的产品。这是错误的,因为较大数字的模数可能会变得非常低(例如,乘积为 1000000008 的路径的模数将为 1,即使存在乘积为仅限2)。

这意味着您应该比较真实产品,而不是取模。由于这些产品可能会变得非常高,因此您应该取它们的对数。这将允许您将产品与简单的double 进行比较。请记住:

log(a*b) = log(a) + log(b)

第四个问题

使用unsigned long long

第 5 个问题

我修复了所有这些问题并在 codechef CHRL4 上提交。除了一个测试用例外,我都接受了。未接受的测试用例是因为超时。这是因为您的算法的复杂度为O(k*n)

您可以使用自下而上的动态编程方法来实现O(n) 的复杂性,而不是自上而下并使用将返回k 先前街道的最小对数值的数据结构。您可以查找sliding window minimum algorithm 以了解如何操作。

参考文献

numeric_limits::max() 我自己的codechef CHRL4解决方案:bottom-up dp + sliding window minimum

【讨论】:

感谢您的努力,但它仍然显示 WA codechef.com/viewsolution/8617807 @wrangler 你解决第三个问题了吗? 我认为第三个问题将针对更高的子任务,但我的 sol 甚至没有通过第一个子任务......。对于 MOD 问题,请参阅codechef.com/viewsolution/8057094。和我的D[i] = ((unsigned long long)D[index] * A[i]) % MOD; 做了同样的事情,但它仍然通过了所有子任务。 我认为问题在于我应用的方法,但据我所知,它通过了所有手动测试用例。方法有什么问题吗? @wrangler 你不理解模数的问题。您正在比较 dp 数组中的值,就好像您没有取模一样。这是错误的。在您的链接中,作者比较了整个产品的log,而不是产品的模数。顺便说一句,还有第四个问题:你使用long int 而不是long long

以上是关于在不使用图表的情况下以最小产品从第一个索引到最后一个索引?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用 Facebook 登录/注销按钮的情况下以编程方式从 Facebook SDK 3.0 注销?

如何在不执行 Queryable 的情况下以通用方式替换 Queryable<T> 中的列

在不耗尽电池的情况下以良好的准确性获取位置更新的最佳方法

如何在不使用 UINavigationController 的情况下以编程方式进入 rootViewController

在不打开联系人应用程序的情况下以编程方式将 vcf 保存到 Android 中的联系人

如何在不单击“下一步”按钮的情况下以重力形式进入下一页