Codeforces Round #593 (Div. 2) E. Alice and the Unfair Game dp

写了个沙雕代码导致一晚上全瞎折腾了,又只出了E,我就想小号上个紫呀,太南了我
E. Alice and the Unfair Game

题意:有 n n n个箱子排成一排,只有一个箱子有桃子,你的目标是不能让 c a t cat cat猜到桃子在哪个箱子里, c a t cat cat一共猜了 m m m次,在 c a t cat cat每次猜箱子之前和之后,你都能把桃子移动到相邻箱子或者不动,定义 ( x , y ) (x, y) (x,y)为桃子一开始在 x x x箱子, c a t cat cat猜了 m m m次后桃子在 y y y箱子,求一共有多少个合法的 ( x , y ) (x, y) (x,y)
解法:首先 ( x , x ) (x,x) (x,x)一定合法,我们枚举 x x x,找一个最大的 y y y,使得 ( x , y ) (x, y) (x,y)合法,那么 a n s + = y − x ans+=y-x ans+=yx,问题转化成求最大的 y y y,假设一共有 6 6 6个箱子, x = 1 x=1 x=1 c a t cat cat猜的箱子分别是 2 , 1 , 3 , 1 , 4 2,1,3,1,4 2,1,3,1,4 c a t cat cat 2 2 2之前我不能把桃子移到 2 2 2号箱子,猜第 3 3 3之前不能把桃子移动到 3 3 3号,猜 4 4 4的之前不能移动到 4 4 4号箱子去,不难发现猜完后桃子最远可以移动到 4 4 4号箱子,我们设 d p [ i ] dp[i] dp[i] c a t cat cat下一次猜 a i a_{i} ai号箱子,当前桃子在 a i − 1 a_{i}-1 ai1号箱子,目标尽量把桃子移到最右边去,接下来必须要原地不动 d p [ i ] dp[i] dp[i]次,不难发现对于 a i a_{i} ai,我们找到第一个 j ( j > i ) j(j > i) j(j>i)满足 a i − i − 1 = a j − j a_{i}-i-1=a_{j}-j aii1=ajj,那么 d p [ i ] = d p [ j ] + 1 dp[i] =dp[j]+1 dp[i]=dp[j]+1,处理完 d p dp dp后,我们枚举 x x x,找到最小的 i i i满足 a i − i = x a_{i}-i=x aii=x,我们有 m + 1 m+1 m+1次移动的机会,那么我们最多可以移到 m i n ( n , x + m + 1 − d p [ i ] ) min(n,x+m+1-dp[i]) min(nx+m+1dp[i])号箱子去,还有一个问题:求最小的 y y y使得 ( x , y ) (x,y) (x,y)合法,这个问题我们可以把 a i a_{i} ai变成 n + 1 − a i n+1-a_{i} n+1ai后再用之前讲得解法去搞定
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e5 + 10;
unordered_map<int, int> mp;
int a[maxn], n, m, d[maxn];
ll calc()
{
    ll ans = 0;
    for (int i = m; i; i--)
    {
        int k = a[i] - i - 1;
        d[i] = d[mp[k]] + 1;
        mp[k + 1] = i;
    }
    for (int i = 1; i <= n; i++)
    {
        int k = mp[i];
        int T = min(n, i + m + 1 - d[k]);
        ans += T - i;
    }
    return ans;
}
int main()
{
    scanf("%d%d", &n, &m);
    ll ans = n;
    for (int i = 1; i <= m; i++)
        scanf("%d", &a[i]);
    if (n == 1)
        return puts("0"), 0;
    ans += calc();
    memset(d, 0, sizeof(d));
    mp.clear();
    for (int i = 1; i <= m; i++)
        a[i] = n + 1 - a[i];
    ans += calc();
    cout << ans;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长沙橘子猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值