2019-2020 ICPC Southwestern European Regional Programming Contest (SWERC 2019-20)

传送门

A. Environment-Friendly Travel

注意到\(N*B\)很小,所以我们利用这个作为状态跑\(dp\)就行。时间复杂度为\(O(10^8)\)左右。
比较套路的\(dp\)了。

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/5/21 16:59:22
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << std::endl; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
  template <template<typename...> class T, typename t, typename... A> 
  void err(const T <t> &arg, const A&... args) {
  for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
  #define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int maxN = 1000 + 5, maxM = 105, MAX = 20005;
 
int T, N, B;
int c[maxN];
int cost[maxN][maxN], w[maxN][maxN];
 
struct Point {
    int x, y;
}p[maxN];
 
int distance(int i, int j) {
    return (int)ceil(hypot(p[i].x - p[j].x, p[i].y - p[j].y) - 1e-9);
}
 
int dis[maxN][maxM];
struct Dijkstra{
    struct node{
        int val, d, u;
        bool operator < (const node &A) const {
            return val > A.val;
        }
    };
    bool vis[maxN][maxM];
    void dij(int s) {
        priority_queue <node> q;
        memset(dis, INF, sizeof(dis));
        memset(vis, 0, sizeof(vis));
        dis[s][0] = 0;
        q.push(node{0, 0, 0});
        while(!q.empty()) {
            node cur = q.top(); q.pop();
            int u = cur.u, d = cur.d;
            if(vis[u][d]) continue;
            vis[u][d] = 1;
            for (int v = 0; v <= N + 1; v++) {
                int dist = w[u][v];
                if (d + dist > B) continue;
                if(dis[v][d + dist] > dis[u][d] + cost[u][v]) {
                    dis[v][d + dist] = dis[u][d] + cost[u][v];
                    q.push(node{dis[v][d + dist], d + dist, v});
                }
            }   
        }
    }
}solver;
 
void run() {
    cin >> p[0].x >> p[0].y;
    int ex, ey; cin >> ex >> ey;
    cin >> B >> c[0] >> T;
    for (int i = 1; i <= T; i++) {
        cin >> c[i];
    }
    cin >> N;
    vector <pair<int, pii>> edges;
    for (int i = 1; i <= N; i++) {
        cin >> p[i].x >> p[i].y;
        int k; cin >> k;
        while (k--) {
            int j, t; cin >> j >> t; ++j;
            edges.push_back(MP(i, MP(j, t)));
        }
    }
    p[N + 1] = Point{ex, ey};
    for (int i = 0; i <= N + 1; i++) {
        for (int j = 0; j <= N + 1; j++) {
            w[i][j] = distance(i, j);
        }
    }
    memset(cost, INF, sizeof(cost));
    for (int i = 1; i <= N; i++) {
        cost[0][i] = c[0] * w[0][i];
        cost[i][N + 1] = c[0] * w[i][N + 1];
    }
    cost[0][N + 1] = c[0] * w[0][N + 1];
    for (auto it : edges) {
        int i = it.fi;
        int j = it.se.fi, t = it.se.se;   
        cost[i][j] = cost[j][i] = min(cost[i][j], c[t] * w[i][j]);
    }
    solver.dij(0);
    int ans = INF;
    for (int i = 0; i <= B; i++) {
        ans = min(ans, dis[N + 1][i]);
    }
    if (ans == INF) ans = -1;
    cout << ans << '\n';
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

B. Biodiversity

签到。

Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ld;
const int MAXN = 1e6 + 5, MAXM = 4e5 + 5, BOUND = 2e5, MOD = 998244353, INF = 0x3f3f3f3f, base = 10000;
const int inv2 = (MOD + 1) >> 1;
const ll INFL = 0x3f3f3f3f3f3f3f3f;
const double PI = acos(-1.0), eps = 1e-9;
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define lc(x) ch[x][0]
#define pii pair<int,int>
#define vi vector<int>
#define vii vector<pair<int,int>>
#define rc(x) ch[x][1]
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define all(a) (a).begin(), (a).end()
#define sz(a) int(a.size())
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define fi first
#define se second
#define MP std::make_pair
#define ri register int
//#define sz(a) int((a).size())
const int N = 2e5,M = (1<<20);
inline int add(int a, int b) {return a + b >= MOD ? a + b - MOD : a + b;}
inline int dec(int a, int b) {return a < b ? a - b + MOD : a - b;}
inline int mul(int a, int b) {return 1ll * a * b % MOD;}
template <typename T>
inline void cmin(T &a,T b){a = min(a,b);}
template <typename T>
inline void cmax(T &a,T b){a = max(a,b);}
ll qpow(ll a,ll b){
    ll ans=1;
    for(;b;b>>=1,a=a*a%MOD)if(b&1)ans=ans*a%MOD;
    return ans;
}
mt19937 mrand(random_device{}());
map<string,int> mp;
void run(){
    int n; cin>>n;
    string tmp;
    rep(i,1,n)cin>>tmp,mp[tmp]++;
    int mx=0;
    string ans;
    for(auto &e:mp){
        if(e.second > mx){
            mx = e.second;
            ans = e.first;
        }
    }
    if(mx > n-mx){
        cout<<ans<<'\n';
    }else cout<<"NONE\n";
}
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    int _=1;
    while(_--)run();
    return 0;
}

C. Ants

直接枚举就行,很大的数没什么用。

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/5/21 13:45:08
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << std::endl; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
  template <template<typename...> class T, typename t, typename... A> 
  void err(const T <t> &arg, const A&... args) {
  for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
  #define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e6 + 5;
 
void run() {
    int n; cin >> n;
    vector <int> a;
    for (int i = 1; i <= n; i++) {
        string s; cin >> s;
        int len = s.length();
        if (s[0] == '-' || len > 100) continue;
        if (len < 9) {
            int x = 0;
            for (int j = 0; j < len; j++) {
                x = x * 10 + s[j] - '0';
            }
            a.push_back(x);
        }
    }
    sort(all(a));
    for (int i = 0, j = 0;; i++, j++) {
        if (j >= sz(a) || i != a[j]) {
            cout << i << '\n';
            return;
        }
    }
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

F. Icebergs

模拟一下。

Code
#include<cstdio>
#include<cmath>
#define REP(i,a,b) for(int i=(a); i<(b); i++)
#define REPE(i,a,b) for(int i=(a); i<=(b); i++)
using namespace std;
#define D Point
#define CD const D
struct D { double x,y;};
double cross(CD&l, CD&r) {return l.x*r.y-l.y*r.x;}
template<class T, int Z>
struct Arr {
	T data[Z]; int n;
	Arr() :n(0) {}
	T&operator[](int z) {return data[z];}
	void push(const T&x) {data[n++]=x;}
	void pop() {n--;}
};
typedef Arr<D,57> Plg;
/*void tubao(Plg &p, Plg &ch) {
	sort(p.data,p.data+p.n);
	int &m=ch.n; m=0;
	REP(i,0,p.n) {
		while(m>1 && cross(ch[m-1]-ch[m-2], p[i]-ch[m-2])<=0 ) m--;
		ch[m++]=p[i];
	}
	int k=m;
	PERE(i,p.n-2,0) {
		while(m>k && cross(ch[m-1]-ch[m-2], p[i]-ch[m-2])<=0) m--;
		ch[m++]=p[i];
	}
	if(p.n>1) m--;
}*/
double area(Plg &p) {
	double ans=0;
	REP(i,0,p.n) {
		ans+=cross(p[i], p[(i+1)%p.n]);;
	}
	return fabs(ans/2);
}
#undef D
#undef CD
Plg p;
int main() {
	int n; scanf("%d", &n);
	double ans=0;
	while(0<n--) {
		
		scanf("%d", &p.n);
		for(int i=0; i<p.n; i++) {
			scanf("%lf%lf", &p[i].x, &p[i].y);
		}
		ans+=area(p);
	}
	printf("%.0lf\n", floor(ans));
	return 0;
}

G. Swapping Places

题意:
给定\(s,s\leq 200\)种物品,给定\(l,l\leq 10000\)组关系,若关系中的两种物品相邻那么就可以交换。
给定长度为\(n\)的序列,每个位置上面为一种物品,现在要求出字典序最小的最终序列。

思路:
我们可以思考一下贪心的做法:

  • 考虑依次确定\(1,2,...,n\)位置上面的数,确定位置\(i\)时,我们贪心将字典序最小的物品往前面移动,最终\(i\)位置上面的数即是最终答案。

简单说一下贪心做法的正确性,我们每一轮优先移动字典序最小的,如果没能到达\(i\),那么当前物种必然不可能位于位置\(i\)
但以上的思想可能复杂度不对or码量较大。
因为我们目前的做法是从后往前,我们可以考虑从前往后,为每种物品给定一个最优位置。那么我们还是按字典序最小的来,我们每次将最优匹配指针往后移动直至不能移动,若当前指针指向的位置为当前物品,那么此时等价于将其往前面移动能够成功到\(i\),所以就确定了答案。

从后往前的话可能会对每一种物品涉及到多个指针,每次取出第一个指针往前移动。但我们可以让这些指针保持不变,用一个指针从前往后移动,这样码量上会好很多。
很巧妙的做法。

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/5/22 10:52:27
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << std::endl; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
  template <template<typename...> class T, typename t, typename... A> 
  void err(const T <t> &arg, const A&... args) {
  for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
  #define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
 
void run() {
    int s, l, n;
    cin >> s >> l >> n;
    vector <string> str(s);
    for (int i = 0; i < s; i++) {
        cin >> str[i];
    }
    sort(all(str));
    map <string, int> mp;
    for (int i = 0; i < s; i++) {
        mp[str[i]] = i;
    }
    map <int, string> mp2;
    for (int i = 0; i < s; i++) {
        mp2[i] = str[i];
    }
    vector <vector <int>> w(s, vector <int> (s));
    for (int i = 0; i < l; i++) {
        string ss, tt; cin >> ss >> tt;
        w[mp[ss]][mp[tt]] = w[mp[tt]][mp[ss]] = 1;
    }
    vector <int> a(n);
    for (int i = 0; i < n; i++) {
        string ss; cin >> ss;
        a[i] = mp[ss]; 
    }
    vector <int> cnt(s);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < s; j++) {
            while (cnt[j] < n && (a[cnt[j]] == -1 || w[a[cnt[j]]][j])) {
                ++cnt[j];
            }
            if (cnt[j] < n && a[cnt[j]] == j) {
                a[cnt[j]] = -1;
                cout << mp2[j] << ' ';
                break;
            }
        }
    }
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

还有一种不那么废脑子的做法,就是我们很容易发现不能交换的物种他们的相对顺序不会发生改变。
我们根据这一点进行建图,若\(i\)位置的物种不能和\(j\)位置的物种交换\((i<j)\),那么连边\(i\rightarrow j\)
那么问题就等价于求出一种字典序最小的拓扑序。
但对每个位置\(j\)这样直接连边的话空间会炸,可能会到\(O(n^2)\)。这里连边其实可以优化:对于每个位置,往前面的物种至多连一条边即可,没必要多连,这样就可以保证拓扑序。
细节见代码:

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/5/22 11:11:26
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << std::endl; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
  template <template<typename...> class T, typename t, typename... A> 
  void err(const T <t> &arg, const A&... args) {
  for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
  #define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
 
struct node {
    int u, val;
    bool operator < (const node &A) const {
        return val > A.val;
    }   
};
 
void run() {
    int s, l, n;
    cin >> s >> l >> n;
    vector <string> str(s);
    for (int i = 0; i < s; i++) {
        cin >> str[i];
    }
    sort(all(str));
    map <string, int> mp;
    for (int i = 0; i < s; i++) {
        mp[str[i]] = i;
    }
    map <int, string> mp2;
    for (int i = 0; i < s; i++) {
        mp2[i] = str[i];
    }
    vector <vector <int>> w(s, vector <int> (s));
    for (int i = 0; i < l; i++) {
        string ss, tt; cin >> ss >> tt;
        w[mp[ss]][mp[tt]] = w[mp[tt]][mp[ss]] = 1;
    }
    vector <int> a(n);
    for (int i = 0; i < n; i++) {
        string ss; cin >> ss;
        a[i] = mp[ss];
    }
    vector <int> in(n), last(s, -1);
    vector <vector <int>> edge(n);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < s; j++) {
            if (last[j] >= 0 && !w[a[last[j]]][a[i]]) {
                ++in[i];
                edge[last[j]].push_back(i);
            }
        }
        last[a[i]] = i;
    }
    priority_queue <node> q;
    for (int i = 0; i < n; i++) {
        if (in[i] == 0) {
            q.push(node{i, a[i]});
        }
    }
    vector <string> ans;
    while (!q.empty()) {
        node cur = q.top(); q.pop();
        ans.push_back(mp2[cur.val]);
        int u = cur.u;
        for (auto v : edge[u]) {
            if (--in[v] == 0) {
                q.push(node{v, a[v]});
            }
        }
    }
    for (auto it : ans) cout << it << ' ';
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

I. Rats

签到。

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/5/21 13:39:18
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << std::endl; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
  template <template<typename...> class T, typename t, typename... A> 
  void err(const T <t> &arg, const A&... args) {
  for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
  #define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
 
void run() {
    int n1, n2, n12;
    cin >> n1 >> n2 >> n12;
    int ans = (n1 + 1) * (n2 + 1) / (n12 + 1) - 1;
    cout << ans << '\n';
 
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

J. Counting Trees

题意:
现有一颗树,每个结点上有个标号,并且满足如下性质,子节点的标号值不小于父亲结点。
现在给出这棵树中序遍历的标号序列。
问有多少棵树满足以上条件。

思路:
显然这棵树的根标号值最小,如果所有标号值各不相同,那么很显然方案数就为\(1\):每次根结点确定,左右子树递归处理。
这给我们提供了一种思路:每次选择最小的作为根,然后分割过后递归进入子树处理。
出现了个问题,如果有多个值最小怎么办?那么这些最小的值的深度肯定是尽可能小的,因为我们最开始的根都选择他们。这些最小值的方案数为卡特兰数。然后这些最小的数将序列分为几个部分,每个部分为一个子树的方案数,当我们最小的数的方案确定时,剩下的其子树的方案也就确定了(感受一下)。
所以就有一个递归做法,序列分割为若干个部分过后递归下去,最后把所有结果乘起来即可。
这样复杂度可能是\(O(n^2)\),代码量也略大。
这是从小到大,我们可以考虑从大到小,显然最终一些数在一个连通块以内,那么他们中间就不可能出现小于的数,否则无论怎样都会被分割。那么可以根据这一点从大到小枚举数,然后确定其连通块,然后可以根据连通块中他们的个数直接计算答案。最后乘进答案就行。
两种核心思想都是等价的,只是第二种想法进一步利用了“区间分割”这一性质,我们可以直接对每种数找到其连通块。
代码如下:

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/5/21 15:22:22
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << std::endl; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
  template <template<typename...> class T, typename t, typename... A> 
  void err(const T <t> &arg, const A&... args) {
  for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
  #define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 2e6 + 5, MOD = 1e9 + 7;
 
int fac[N], inv[N], INV[N];
int qpow(ll a, ll b) {
    ll res = 1;
    while (b) {
        if (b & 1) res = res * a % MOD;   
        a = a * a % MOD;
        b >>= 1;
    }
    return res;
}
 
int C(int n, int m) {
    return 1ll * fac[n] * inv[m] % MOD * inv[n - m] % MOD;
}
 
int cat(int n) {
    return 1ll * C(2 * n, n) * INV[n + 1] % MOD;
}
int f[N][21];
int n;
void Get_st(){
    for(int j=1;j<=20;j++)
        for(int i=1;i<=n;i++)
            if(i+(1<<(j-1))<=n) f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
int Get_min(int l,int r){
    if (l > r) return INF;
    int k=0;
    while(1<<(k+1)<=r-l+1) k++;
    return min(f[l][k],f[r-(1<<k)+1][k]);
} 
vector <int> p[N];
 
void run() {
    cin >> n;
    fac[0] = 1;
    for (int i = 1; i < N; i++) fac[i] = 1ll * fac[i - 1] * i % MOD;
    inv[N - 1] = qpow(fac[N - 1], MOD - 2);
    for (int i = N - 2; i >= 0; i--) inv[i] = 1ll * inv[i + 1] * (i + 1) % MOD;
    for (int i = N - 1; i >= 0; i--) INV[i] = qpow(i, MOD - 2);
    memset(f, INF, sizeof(f));
    for (int i = 1; i <= n; i++) {
        int x; cin >> x;
        f[i][0] = x;
        p[x].push_back(i);
    }
    Get_st();
    int ans = 1;
    for (int i = N - 1; i >= 0; i--) if (sz(p[i])) {
        int cnt = 1;
        for (int j = 1; j < sz(p[i]); j++) {
            int L = p[i][j - 1], R = p[i][j];
            if (Get_min(L + 1, R - 1) > i) {
                ++cnt;
            } else {
                if (cnt > 1) {
                    ans = 1ll * ans * cat(cnt) % MOD;
                }
                cnt = 1;
            }
        }
        if (cnt > 1) {
            ans = 1ll * ans * cat(cnt) % MOD;
        }
    }
    cout << ans << '\n';
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

K. Birdwatching

题意:
给定一颗有根树,并且给定一个关键点\(t\),问有多少点只有一条路径到达关键点\(t\),且这条路径为\(u\rightarrow t\)

思路:
暴力的做法:

  • 对于每个点删除\(u\rightarrow t\)这条边,然后直接\(dfs\)看能不能走到\(t\)

显然时间复杂度为\(O(n^2)\),不能承受。
考虑对于所有的点删除到\(t\)的这条边,将这样的点放入集合\(s\)中。显然如果\(u\in s\),能够到达\(v\in s\),那么\(u\)就不合法。
注意到这是一个可达性的问题,我们可以考虑建反图,然后从\(u\in s\)出发进行染色。
若一个点只被自己染色,那么就说明这个点合法。否则被其他点染色就不合法。
这样考虑复杂度还是没有变化,我们可以给每个点限制染色个数为\(2\),这样每个点至多被遍历两次,复杂度就降下来变为\(O(n)\)了。
也是一个很巧妙的题。

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/5/21 18:10:44
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << std::endl; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
  template <template<typename...> class T, typename t, typename... A> 
  void err(const T <t> &arg, const A&... args) {
  for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
  #define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
 
int n, m, t;
vector <int> G[N];
int c1[N], c2[N];
 
void dfs(int u, int c) {
    if (u == t) return;
    if (c1[u] == -1) {
        c1[u] = c;
    } else if(c2[u] == -1) {
        if (c1[u] == c) return;
        c2[u] = c;
    } else return;
    for (auto v : G[u]) dfs(v, c);
}
 
void run() {
    cin >> n >> m >> t;
    memset(c1, -1, sizeof(c1));
    memset(c2, -1, sizeof(c2));
    for (int i = 1; i <= m; i++) {
        int u, v; cin >> u >> v;
        G[v].push_back(u);
    }
    for (auto it : G[t]) {
        dfs(it, it);
    }
    vector <int> ans;
    for (int i = 0; i < n; i++) if (c1[i] == i && c2[i] == -1) {
        ans.push_back(i);
    }
    cout << sz(ans) << '\n';
    for (auto it : ans) {
        cout << it << '\n';
    }
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}
posted @ 2020-05-23 11:20  heyuhhh  阅读(1026)  评论(0编辑  收藏  举报