【问题标题】:Codeforces 607A. Getting wrong answer代码部队 607A。得到错误的答案
【发布时间】:2020-03-09 07:06:31
【问题描述】:

在数轴上的不同位置有 n 个信标。第 i 个信标具有位置 ai 和功率电平 bi。当第 i 个信标被激活时,它会破坏其左侧(坐标递减方向)在距离 bi 内的所有信标。然而,信标本身并没有被破坏。埼玉将从右到左一次激活一个信标。如果信标被摧毁,则无法激活。
埼玉希望杰诺斯在所有现有信标的右侧添加一个严格的信标,具有任何位置和任何功率级别,以便尽可能少地破坏信标。请注意,Genos 放置信标意味着它将是第一个激活的信标。帮助 Genos 找出可以被摧毁的最小信标数量。

这里是问题的链接 (http://codeforces.com/contest/607/problem/A) Screenshot of question.
我的方法是使用 Dp 查找未销毁的最小对象数。如果我只有 i 个元素,则 dp[i]= 未销毁的最小对象数。
- 当第 i 个对象被右侧的某个元素破坏时,让 inc 是答案。因此 inc = 1 + dp[i-1]

- 当第 i 个对象没有被右侧的某个元素破坏时,让 exc 为答案。由于第 i 个元素没有被破坏,所以当我们引爆它时,它会破坏其左边界(a[i]-b[i])内的所有元素。假设它可以破坏左侧的 lbd 个元素。因此 exc = lbd + dp[i-lbd]

现在 dp[i] = min{ inc , exc }。最后返回 dp[n]

但是我的代码在测试用例 11 中给出了错误的答案。如果我的逻辑或代码有问题,谁能帮助我?
这是我的代码 sn-p
ll = long long int
pll = 一对长整数
rep(i,0,n) = 从 0 到 n 的循环

void solve(){
    ll n;
    cin>>n;
    vector<pll> a(n);
    vector<ll> b(n);
    rep(i,0,n){
        cin>>a[i].first>>a[i].second;
        b[i]=a[i].first;
    }
    sort(b.begin(),b.end());
    sort(a.begin(),a.end(),cmp);
    vector<ll> dp(n+1,0);
    rep(i,1,n+1){
        ll inc = 1+ dp[i-1];
        ll temp = a[i-1].first-a[i-1].second;
        ll lb = lower_bound(b.begin(),b.end(),temp)-b.begin();
        ll exc=(i-lb-1)+dp[lb];
        dp[i]=min(inc,exc);
    }
    cout<<dp[n]<<endl;
}


完整代码链接https://ideone.com/THbCLK

【问题讨论】:

  • b[i]=a[i].first; 似乎很可疑。你真的需要b 向量吗?
  • 不,我不需要 b[i],我只是使用 b[i] 以便可以在 b 上使用 lower_bound,否则,我必须编写一些额外的代码以便我可以在 a 上使用 lower_bound(它是对的向量)。
  • 我认为您将我的 b 与问题中提到的功率级别 b[i] (等于 a[i].second )混淆了。我的“b”向量以递增顺序指示信标的位置。抱歉,我在命名变量时应该小心。我的逻辑需要找到直到信标可以摧毁其他信标的位置。 @JanezKuhar
  • 感谢您的解决方案。我得到了你的方法。但我只是好奇为什么我的方法不起作用。
  • 我已经用另一个解决方案(解决方案 #1)更新了我的答案。是否更清楚为什么您的方法不起作用?

标签: data-structures c++14 dynamic-programming


【解决方案1】:

问题

这就是你定义dp[i]的方式:

dp[i] = 销毁的最小对象数如果我只有 i 个元素

首先,我认为有一个错字,你的意思是这样的:

dp[i] = 销毁的最小对象数如果我只有 i 个元素

其次,如果你只有 i 元素,那么 i-th 元素永远不会被其右侧的任何信标破坏(因为没有任何信标) .因此,考虑 i-th 信标被其右侧的某物破坏的情况是愚蠢的。

解决方案在于重新表述您的子问题 (dp[i])。


解决方案 #1

让我们这样定义dp[i]

// dp[i] ... The number of beacons destroyed after lighting the i-th beacon

当我们点亮第 i-th 个信标时:

  1. 它会摧毁其功率范围内的所有信标。
  2. 一些信标之前可能已经被摧毁,不受第 i-th 个信标的影响。

结合 1. 和 2. 我们得到 dp[i] 的以下表达式:

// lb = Lower Bound - the index of the left-most beacon
// that is still in the power range of the i-th beacon
dp[i] = lb == 0 ? i : i - lb + dp[lb-1];

注意: 最多必须销毁n-1 信标。点亮第 i 个信标后,dp[i] 信标被销毁(第 i 个信标的左侧),至多n-i-1 信标仍然可以被销毁(第 i 个信标的右侧)。

考虑到这一点,这就是最终答案的产生方式:

ll ans = n - 1;
rep(i, 0, n) {
    ans = min(dp[i] + n - i - 1, ans);
}

Here 是我的“已接受”解决方案,基于您的代码和this submission


解决方案 #2

让我们这样定义dp[i]

// dp[i] ... The number of beacons lit after lighting the i-th beacon

当我们点亮 i-th 信标时,可能会发生以下两种情况之一:

  1. i-th 个信标非常强大,它可以杀死其左侧的所有 个信标,使其成为唯一点亮的信标
  2. i-th 信标只会击倒其左侧的 一些 信标

结合 1. 和 2. 我们得到 dp[i] 的以下表达式:

// lb = Lower Bound - the index of the first beacon left of the
// i-th beacon that is out of the power range of the i-th beacon
dp[i] = lb < 0 ? 1 : 1 + dp[lb];

为了解决问题,必须找到最大值 dp[i]:

// minimum_number_of_beacons_destroyed = n - maximum_number_of_beacons_lit

Here 是我的“已接受”解决方案,基于您的代码和this submission

还有一个官方的editorial,但是我不清楚这个解决方案。


补充说明

  • Genos 添加的信标无关紧要 - 他始终可以将其放置在最右侧,以免影响任何现有的信标,这就是为什么该信息不会增加问题的原因。
  • 必须事先按位置升序对信标进行排序。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-06
    • 2019-05-06
    • 2019-02-14
    • 2016-10-23
    • 1970-01-01
    • 2014-11-21
    相关资源
    最近更新 更多