「题解」Solution P3275

Description

P3275
给定 (n) 个整数 (t_i)(k) 个不等式,这 (k) 个不等式有如下几种

  • (t_i=t_j)
  • (t_i<t_j)
  • (t_i ge t_j)
  • (t_i>t_j)
  • (t_ile t_j)
    最后输出

[sumlimits_{i=1}^nt_i ]

如果无解输出 (-1)

Solution

建议先看一看差分约束前置知识。

差分约束,但这种形式还是很难搞差分,所以我们要转化一下,成这样:

  • (t_i ge t_j) or (t_j ge t_i)
  • (t_j ge t_i+1)
  • (t_i ge t_j)
  • (t_i ge t_j+1)
  • (t_j ge t_i)

我们一旦在差分约束题中发现 (a ge b) 的形式,那么我们就要开始算 最长路

并且还有一个约束条件:(t_i >1)

注意最长路与最短路的几个区别:

  • (dist_i=min{dist_j+<i,j>}) 的转化式要变为 (dist_i=max{dist_j+<i,j>})
  • (dist_i) 的初始值要从 ( m inf) 变为 ( m - inf)

对于这道题,因为 (t_i > 1),所以在差分约束建超级源点的时候要注意边权 (w) 要设为 (1)

然后根据差分约束模板的思路转化就可以。

Code 1
#include <bits/stdc++.h>

using namespace std;

struct node {
    int val, next, len;
} e[1000086];

int n, k;
int cnt;
int head[1000086];
int dist[1000086];
int sum[1000086];
int vis[1000086];
int S[1000086];
const int inf = 0x3f3f3f3f;

void AddEdge (int u, int v, int w) {
    e[++cnt].val = v;
    e[cnt].next = head[u];
    e[cnt].len = w;
    head[u] = cnt;
}

bool SPFA () {
    queue <int> q;
    int s = 0;
    for (int i = 1; i <= n; i++)
        dist[i] = -inf;
    dist[s] = 0;
    sum[s] = 1;
    vis[s]++;
    q.push(s);
    while (!q.empty()) {
        int cur = q.front();
        q.pop();
        sum[cur] = 0;
        for (int p = head[cur]; p > 0; p = e[p].next)
            if (dist[e[p].val] < dist[cur] + e[p].len) {
                dist[e[p].val] = dist[cur] + e[p].len;
                vis[e[p].val]++;
                if (vis[e[p].val] >= n + 1)
                    return true;
                if (!sum[e[p].val]) {
                    q.push(e[p].val);
                    sum[e[p].val] = 1;
                }
            }
    }
    return false;
}

int main () {
    scanf("%d%d", &n, &k);
    for (int i = 1, opt, u, v; i <= k; i++) {
        scanf("%d%d%d", &opt, &u, &v);
        if (opt == 1) AddEdge(u, v, 0), AddEdge(v, u, 0);
        if (opt == 2) AddEdge(u, v, 1);
        if (opt == 3) AddEdge(v, u, 0);
        if (opt == 4) AddEdge(v, u, 1);
        if (opt == 5) AddEdge(u, v, 0);
    }
    for (int i = 1; i <= n; i++)
    	AddEdge(0, i, 1);
    if (SPFA()) {
    	printf("-1");
    	return 0;
	}
    int ans = 0;
    for (int i = 1; i <= n; i++)
        ans += dist[i];
    printf("%d", ans);
    return 0;
}

预测得分:(80)
wdnmd …… 这 TLE 是咋回事?

所以我们要特判

Code 2
#include <bits/stdc++.h>

using namespace std;

struct node {
    int val, next, len;
} e[1000086];

int n, k;
int cnt;
int head[1000086];
int dist[1000086];
int sum[1000086];
int vis[1000086];
int S[1000086];
const int inf = 0x3f3f3f3f;

void AddEdge (int u, int v, int w) {
    e[++cnt].val = v;
    e[cnt].next = head[u];
    e[cnt].len = w;
    head[u] = cnt;
}

bool SPFA () {
    queue <int> q;
    int s = 0;
    for (int i = 1; i <= n; i++)
        dist[i] = -inf;
    dist[s] = 0;
    sum[s] = 1;
    vis[s]++;
    q.push(s);
    while (!q.empty()) {
        int cur = q.front();
        q.pop();
        sum[cur] = 0;
        for (int p = head[cur]; p > 0; p = e[p].next)
            if (dist[e[p].val] < dist[cur] + e[p].len) {
                dist[e[p].val] = dist[cur] + e[p].len;
                vis[e[p].val]++;
                if (vis[e[p].val] >= n + 1)
                    return true;
                if (!sum[e[p].val]) {
                    q.push(e[p].val);
                    sum[e[p].val] = 1;
                }
            }
    }
    return false;
}

int main () {
    scanf("%d%d", &n, &k);
    for (int i = 1, opt, u, v; i <= k; i++) {
        scanf("%d%d%d", &opt, &u, &v);
        if (opt != 1 && opt != 3 && opt != 5 && u == v) {
        	printf("-1");
        	return 0;
		}
        if (opt == 1) AddEdge(u, v, 0), AddEdge(v, u, 0);
        if (opt == 2) AddEdge(u, v, 1);
        if (opt == 3) AddEdge(v, u, 0);
        if (opt == 4) AddEdge(v, u, 1);
        if (opt == 5) AddEdge(u, v, 0);
    }
    for (int i = 1; i <= n; i++)
    	AddEdge(0, i, 1);
    if (SPFA()) {
    	printf("-1");
    	return 0;
	}
    int ans = 0;
    for (int i = 1; i <= n; i++)
        ans += dist[i];
    printf("%d", ans);
    return 0;
}

预测得分:(90)
这卡常 …… 还能卡一个 TLE

那么我们还可以怎么优化呢?
用 deque 一优化就可以了!

Code 3
#include <bits/stdc++.h>

using namespace std;

struct node {
    int val, next, len;
} e[1000086];

int n, k;
int cnt;
int head[1000086];
int dist[1000086];
int sum[1000086];
int vis[1000086];
int S[1000086];
const int inf = 0x3f3f3f3f;

void AddEdge (int u, int v, int w) {
    e[++cnt].val = v;
    e[cnt].next = head[u];
    e[cnt].len = w;
    head[u] = cnt;
}

bool SPFA () {
    deque <int> q;
    int s = 0;
    for (int i = 1; i <= n; i++)
        dist[i] = -inf;
    dist[s] = 0;
    sum[s] = 1;
    vis[s]++;
    q.push_front(s);
    while (!q.empty()) {
        int cur = q.front();
        q.pop_front();
        sum[cur] = 0;
        for (int p = head[cur]; p > 0; p = e[p].next)
            if (dist[e[p].val] < dist[cur] + e[p].len) {
                dist[e[p].val] = dist[cur] + e[p].len;
                vis[e[p].val]++;
                if (vis[e[p].val] >= n + 1)
                    return true;
                if (!sum[e[p].val]) {
                    q.push_front(e[p].val);
                    sum[e[p].val] = 1;
                }
            }
    }
    return false;
}

int main () {
    scanf("%d%d", &n, &k);
    for (int i = 1, opt, u, v; i <= k; i++) {
        scanf("%d%d%d", &opt, &u, &v);
        if (opt != 1 && opt != 3 && opt != 5 && u == v) {
        	printf("-1");
        	return 0;
		}
        if (opt == 1) AddEdge(u, v, 0), AddEdge(v, u, 0);
        if (opt == 2) AddEdge(u, v, 1);
        if (opt == 3) AddEdge(v, u, 0);
        if (opt == 4) AddEdge(v, u, 1);
        if (opt == 5) AddEdge(u, v, 0);
    }
    for (int i = 1; i <= n; i++)
    	AddEdge(0, i, 1);
    if (SPFA()) {
    	printf("-1");
    	return 0;
	}
    long long ans = 0;
    for (int i = 1; i <= n; i++)
        ans += (1ll * dist[i]);
    printf("%lld", ans);
    return 0;
}

预测得分:(100)
AC Record

By Shuchong
2020.7.15