• [USACO16JAN]愤怒的奶牛Angry Cows


    传送门

    一道神奇的DP………(鬼知道他为什么在tarjan里面)

    一开始可能会考虑贪心或者什么其他神奇的算法,不过还是DP比较靠谱。

    我们用f[i]表示摧毁所有i左侧的炸 药包最少需要的能量,用g[i]表示摧毁所有i右侧的炸 药包最少需要的能量。

    那么我们只要找到满足j < i,a[i] - a[j] > f[j]+1的最后一个j炸 药包,就可以更新f[i]的值,f[i]  = min(f[i],a[i]-a[j],f[j]+1);

    同样的g也是同理。

    为什么这么找呢……因为首先我们发现如果a[i]-a[j]比f[j]+1还要小的话,那么从i点引发的爆炸是可以波及到j点的,所以并不需要更新答案,直到不满足的时候我们才更新。

    最后枚举爆炸的点就可以了。

    然后这题有个技巧,如果往数轴上投炸 药你要么投在点上要么投在两者中间,也就是只可能有整数或者.5的情况。这样直接把所有数据×2计算最后/2就可以了。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<queue>
    #include<set>
    #include<map>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    
    using namespace std;
    typedef long long ll;
    const int M = 50005;
    const int INF = 2000000009;
    
    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
        if(ch == '-') op = -1;
        ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
        }
        return ans * op;
    }
    
    int n,f[M],g[M],a[M],head,tail,ans = INF;
    int main()
    {
        n = read();
        rep(i,1,n) a[i] = read() << 1;
        sort(a+1,a+1+n);
        n = unique(a+1,a+1+n) - a - 1;
        rep(i,1,n) f[i] = g[i] = INF;
        f[1] = -2;
        rep(i,2,n)
        {
        while(head + 1 < i && a[i] - a[head+1] > f[head+1] + 2) head++;
        f[i] = min(f[head+1] + 2,a[i] - a[head]);
        }
        g[n] = -2,tail = n;
        per(i,n-1,1)
        {
        while(tail - 1 > i && a[tail-1] - a[i] > g[tail-1] + 2) tail--;
        g[i] = min(a[tail] - a[i],g[tail-1] + 2);
        }
        //rep(i,1,n) printf("%d %d
    ",f[i],g[i]);
        head = 1,tail = n;
        while(head < tail)
        {
        ans = min(ans,max((a[tail] - a[head]) >> 1,2 + max(g[tail],f[head])));
        if(f[head+1] < g[tail-1]) head++;
        else tail--;
        }
        printf("%.1lf
    ",(double)ans / 2.0);
        return 0;
    }
     
  • 相关阅读:
    SQL查询语句 group by后, 字符串合并
    正则表达式对象模型
    C#正则表达式编程(四):正则表达式
    C#正则表达式编程(三):Match类和Group类用法
    C#正则表达式编程(二):Regex类用法
    C#正则表达式编程(一):C#中有关正则的类
    正则表达式中-分组构造
    正则表达式-定位点
    正则表达式-字符类减法
    正则表达式-匹配标点符号
  • 原文地址:https://www.cnblogs.com/captain1/p/9680913.html
Copyright © 2020-2023  润新知