• 「JOISC 2015 Day 1」卡片占卜


    博主的 BiBi 时间

    今天考试全线炸裂。这道 (T1) 连电风扇的分都没拿到。(我竟然还专门思考了一波不用线段树 (QwQ)

    Solution

    我们可以把 ([l,r]) 的翻转看作差分:把 (l) 加一,把 (r+1) 加一(注意这是在模二意义下的)。

    (l_i,r_i) 分别为第 (i) 段的起点与终点。最后我们要求将 (val[l_2]==val[r_2+1]==val[l_4]==val[r_4+1]==1)(注意这是在模二意义下的)。

    我们可以把这个玩意转化成图论问题:从某个起点(例如 (l_2))出发,经过某几条边到达终点(例如 (r_2+1))。

    可以证明这个方法的正确性:假设有 (i<j<k),有 (edge(i,k))(edge(k,j)),其实就是 (i->j) 也就是操作两个区间,向其他方向的同理。

    我们有三种方法达到目的(注意之后的 (a,b,c,d,e) 都已经是代表下标了):

    100111000011111
    a b  c   d    e
    
    • ([a+1,b+1],[c+1,d+1])
    • ([a+1,c+1],[b+1,d+1])
    • ([a+1,d+1],[b+1,c+1])

    注意 (Dijkstra) 里面的 (vis[s]) 不要赋值,会错。

    Code

    #include <queue>
    #include <cstdio>
    #include <iostream>
    using namespace std;
    typedef long long ll;
    
    const int N = 1e5 + 5;
    const ll inf = 1e18;
    
    int n, a[10], nxt[N << 1], to[N << 1], head[N * 5], cnt;
    ll ans = inf, dis[N * 5], w[N << 1];
    bool vis[N * 5];
    struct node {
    	ll w; int id;
    	
    	node() {}
    	
    	node(const ll W, const int Id) {w = W; id = Id;}
    	
    	bool operator < (const node x) const {
    		return w > x.w;
    	}	
    };
    priority_queue <node> q;
    
    int read() {
    	int x = 0, f = 1; char s;
    	while((s = getchar()) > '9' || s < '0') if(s == '-') f = -1;
    	while(s <= '9' && s >= '0') x = (x << 1) + (x << 3) + (s ^ 48), s = getchar();
    	return x * f;
    }
    
    void addEdge(const int u, const int v, const ll val) {
    	nxt[++ cnt] = head[u], to[cnt] = v, w[cnt] = val, head[u] = cnt;
    }
    
    ll Dijkstra(const int s, const int t) {
    	for(int i = 1; i <= a[5] + 1; ++ i) dis[i] = inf, vis[i] = 0;
    	dis[s] = 0;
    	q.push(node(0, s));
    	while(! q.empty()) {
    		int u = q.top().id; q.pop();
    		if(vis[u]) continue;
    		vis[u] = 1;
    		for(int i = head[u]; i; i = nxt[i])
    			if(dis[to[i]] > dis[u] + w[i]) dis[to[i]] = dis[u] + w[i], q.push(node(dis[to[i]], to[i]));
    	}
    	return dis[t] == inf ? -1 : dis[t];
    }
    
    int main() {
    	int u, v; ll r1, r2;
    	for(int i = 1; i <= 5; ++ i) a[i] = read() + a[i - 1];
    	n = read();
    	for(int i = 1; i <= n; ++ i) {
    		u = read(), v = read();
    		addEdge(u, v + 1, v - u + 1), addEdge(v + 1, u, v - u + 1);
    	}
    	r1 = Dijkstra(a[1] + 1, a[2] + 1), r2 = Dijkstra(a[3] + 1, a[4] + 1);
    	if(r1 != -1 && r2 != -1) ans = min(ans, r1 + r2);
    	r1 = Dijkstra(a[1] + 1, a[3] + 1), r2 = Dijkstra(a[2] + 1, a[4] + 1);
    	if(r1 != -1 && r2 != -1) ans = min(ans, r1 + r2);
    	r1 = Dijkstra(a[1] + 1, a[4] + 1), r2 = Dijkstra(a[2] + 1, a[3] + 1);
    	if(r1 != -1 && r2 != -1) ans = min(ans, r1 + r2);
    	printf("%lld
    ", ans == inf ? -1 : ans);
    	return 0;
    }
    
  • 相关阅读:
    IO复习
    递归
    转换流
    编码与解码
    打印流(printStream)
    Properties
    【转】将Visual Studio武装到底
    【转】VS2008中的自定义格式化代码
    C++开发工具的常用插件
    抽烟的注意事项
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/13055233.html
Copyright © 2020-2023  润新知