codeforces 704B - Ant Man [想法题]

题目链接:http://codeforces.com/problemset/problem/704/B

--------------------------------------------------------------------------------

比赛时最远也就猜到了拆公式,算贡献这一步 然后就$GG$了

结束后问了$Randolph87$ 他给了一个"括号匹配"的思路

感觉这个思路比官方题解更可做 然后我就按照这个思路开始思考

对于非起点非终点外的所有点 有这四种情况

左入左出 左入右出 右入左出 右入右出

每当加入一个新的点

如果它是右入右出则当前区间的入度 $+1$ 出度 $+1$

如果是左入左出则当前区间的入度 $-1$ 出度 $-1$

另外两种情况则是入度出度都不改变

(此处度数是对于整个区间讲的 或者说这个区间对应的有向图还需要增加$x$个入度和$y$个出度才能构成一个环)

假设题目不限定起点终点 只要求一个回路 那么对于所有的点都这样做

并且保证中间状态中入度出度都为正数 最终状态入度出度都为$0$即可

然而题目是有起点和终点限制的一条路径

因此我们可以强行连一条从终点出从起点入的代价为$0$的边

.

.

.

按照这个思路做下去 一部分人会$WA5$

原因是在实现的时候 有可能只是限定了终点有一条方向向着起点的边

于是中间还可能混入其他的点 并没有保证终点和起点的直接连接

为了满足这个要求 我们可以在扫描到起点和终点之间的点的时候

强行使得 入度$-1(s < e$时$)$ / 出度 $-1(s > e$时$)$

这样就可以把这一部分完美地解决了

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int N = 5010;
long long f[N][N];
bool valid[N][N];
int x[N], a[N], b[N], c[N], d[N];
int n, s, e;
void update(long long &x, long long y, bool &z)
{
    if(!z)
    {
        z = 1;
        x = y;
        return;
    }
    x = min(x, y);
}
int main()
{
    scanf("%d%d%d", &n, &s, &e);
    for(int i = 1; i <= n; ++i)
        scanf("%d", &x[i]);
    for(int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    for(int i = 1; i <= n; ++i)
        scanf("%d", &b[i]);
    for(int i = 1; i <= n; ++i)
        scanf("%d", &c[i]);
    for(int i = 1; i <= n; ++i)
        scanf("%d", &d[i]);
    valid[0][0] = 1;
    int delta = 0;
    for(int i = 1; i <= n; ++i)
    {
        if(i == min(s, e))
            delta = s < e ? 1 : -1;
        else if(i == max(s, e))
            delta = 0;
        if(i != s && i != e)
            for(int j = 0; j <= i && j <= n - i; ++j)
            {
                if(j && valid[i - 1][j - 1])
                    update(f[i][j], f[i - 1][j - 1] + b[i] + d[i] - x[i] * 2, valid[i][j]);
                if((j || i == n) && valid[i - 1][j + 1])
                    update(f[i][j], f[i - 1][j + 1] + a[i] + c[i] + x[i] * 2, valid[i][j]);
                if(j && valid[i - 1][j])
                {
                    if(j > 1 || !delta)
                        update(f[i][j], f[i - 1][j] + min(a[i] + d[i], b[i] + c[i]), valid[i][j]);
                    else if(delta == 1)
                        update(f[i][j], f[i - 1][j] + a[i] + d[i], valid[i][j]);
                    else
                        update(f[i][j], f[i - 1][j] + b[i] + c[i], valid[i][j]);
                }
            }
        else if(i == s)
            for(int j = 0; j <= i && j <= n - i; ++j)
            {
                if(s < e && j && valid[i - 1][j - 1])
                    update(f[i][j], f[i - 1][j - 1] + d[i] - x[i], valid[i][j]);
                if(s < e && j && valid[i - 1][j])
                    update(f[i][j], f[i - 1][j] + c[i] + x[i], valid[i][j]);
                if(s > e && (j || i == n) && valid[i - 1][j + 1])
                    update(f[i][j], f[i - 1][j + 1] + c[i] + x[i], valid[i][j]);
                if(s > e && j && valid[i - 1][j])
                    update(f[i][j], f[i - 1][j] + d[i] - x[i], valid[i][j]);
            }
        else
            for(int j = 0; j <= i && j <= n - i; ++j)
            {
                if(s < e && (j || i == n) && valid[i - 1][j + 1])
                    update(f[i][j], f[i - 1][j + 1] + a[i] + x[i], valid[i][j]);
                if(s < e && j && valid[i - 1][j])
                    update(f[i][j], f[i - 1][j] + b[i] - x[i], valid[i][j]);
                if(s > e && j && valid[i - 1][j - 1])
                    update(f[i][j], f[i - 1][j - 1] + b[i] - x[i], valid[i][j]);
                if(s > e && j && valid[i - 1][j])
                    update(f[i][j], f[i - 1][j] + a[i] + x[i], valid[i][j]);
            }
    }
    printf("%lld\n", f[n][0]);
    return 0;
}

 

posted @ 2016-08-08 14:58  sagitta  阅读(733)  评论(0编辑  收藏  举报