• 2018冬令营模拟测试赛(十七)


    2018冬令营模拟测试赛(十七)

    [Problem A]Tree

    试题描述

    QAQ

    输入

    见“试题描述

    输出

    见“试题描述

    输入示例

    见“试题描述

    输出示例

    见“试题描述

    数据规模及约定

    见“试题描述

    题解

    这个数据范围肯定是树上背包了。

    (f(i, j, k)) 表示子树 (i) 中选择了 (j) 个节点,路径与根的连接情况为 (k),具体地:

    • (k = 0) 时,路径的两个端点都在子树内部;
    • (k = 1) 时,路径的一个端点是 (i),另一个端点在子树内部;
    • (k = 2) 时,路径的两个端点都是 (i)

    这个树上背包的过程是:初始时只有选择根节点的情况(此时路径两端点当然都是 (i)),然后考虑加入一个子树,那么现在就是要讨论新路径的两个端点是否在根,若不在根,则在新加入的子树中或者原来的子树中;具体地:

    • 两个节点都不在根,那么有三种情况:
      • 两个端点都在原来的子树中;
      • 两个端点都在新加入的子树中;
      • 一个端点在新加入的子树中,另一个在原来子树中。
    • 一个节点在根,那么有两种情况:
      • 另一个节点在原来子树中;
      • 另一个节点在新加入的子树中。
    • 两个节点都在根。

    转移的时候把路径的首尾接好,设新加入的子树是 (j),算好 (i ightarrow j) 这条边经过一次还是两次。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    #define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
    #define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; i--)
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 3010
    #define maxm 6010
    #define oo 700000000
    
    int n, m, K, head[maxn], nxt[maxm], to[maxm], dist[maxm];
    
    void AddEdge(int a, int b, int c) {
    	to[++m] = b; dist[m] = c; nxt[m] = head[a]; head[a] = m;
    	swap(a, b);
    	to[++m] = b; dist[m] = c; nxt[m] = head[a]; head[a] = m;
    	return ;
    }
    
    void upd(int& a, int b) {
    	if(a > b) a = b;
    	return ;
    }
    int f[maxn][maxn][2][2], siz[maxn];
    void dp(int u, int fa) {
    	f[u][1][1][1] = 0;
    	siz[u] = 1;
    	for(int e = head[u]; e; e = nxt[e]) if(to[e] != fa) {
    		dp(to[e], u);
    		dwn(i, siz[u], 1) dwn(j, siz[to[e]], 1) {
    			upd(f[u][i+j][0][0], f[u][i][0][0] + f[to[e]][j][1][1] + (dist[e] << 1));
    			upd(f[u][i+j][0][0], min(f[to[e]][j][0][0], min(f[to[e]][j][0][1], f[to[e]][j][1][1])) + f[u][i][1][1] + (dist[e] << 1));
    			upd(f[u][i+j][0][0], f[u][i][0][1] + min(f[to[e]][j][0][1], f[to[e]][j][1][1]) + dist[e]);
    			upd(f[u][i+j][0][1], f[u][i][0][1] + f[to[e]][j][1][1] + (dist[e] << 1));
    			upd(f[u][i+j][0][1], f[u][i][1][1] + min(f[to[e]][j][0][1], f[to[e]][j][1][1]) + dist[e]);
    			upd(f[u][i+j][1][1], f[u][i][1][1] + f[to[e]][j][1][1] + (dist[e] << 1));
    		}
    		siz[u] += siz[to[e]];
    	}
    	// rep(i, 0, siz[u]) printf("[%d][%d]: %d %d %d
    ", u, i, f[u][i][0][0], f[u][i][0][1], f[u][i][1][1]);
    	return ;
    }
    
    int main() {
    	n = read(); K = read();
    	rep(i, 1, n - 1) {
    		int a = read(), b = read(), c = read();
    		AddEdge(a, b, c);
    	}
    	
    	rep(i, 1, n) rep(j, 0, n) rep(s, 0, 1) rep(t, 0, 1) f[i][j][s][t] = oo;
    	dp(1, 0);
    	
    	int ans = oo;
    	rep(i, 1, n) upd(ans, min(f[i][K][0][0], min(f[i][K][0][1], f[i][K][1][1])));
    	printf("%d
    ", ans);
    	
    	return 0;
    }
    

    [Problem B]Tower

    试题描述

    TwT

    QwQ

    输入

    见“试题描述

    输出

    见“试题描述

    输入示例

    见“试题描述

    输出示例

    见“试题描述

    数据规模及约定

    见“试题描述

    题解

    这个题直接上哈希……

    由于在首尾添加一个字符,答案只可能加 (1) 或加 (2),于是分别维护一下首尾正反长度为 (nowans)(nowans + 1) 的串的哈希值就好了,有必要再开一个串记录当前串长什么样。然后记得把所有东西可持久化一下(包括当前串的首尾指针、答案、(8) 种哈希值),其实就是用个栈维护一下,到撤销的时候直接把栈的顶指针减去它撤回的步数即可。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    #include <vector>
    using namespace std;
    #define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
    #define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; i--)
    
    const int BufferSize = 1 << 16;
    char buffer[BufferSize], *Head, *Tail;
    inline char Getchar() {
        if(Head == Tail) {
            int l = fread(buffer, 1, BufferSize, stdin);
            Tail = (Head = buffer) + l;
        }
        return *Head++;
    }
    int read() {
        int x = 0, f = 1; char c = Getchar();
        while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
        while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
        return x * f;
    }
    
    #define maxn 10000010
    #define UI unsigned int
    #define LL long long
    #define rate 233
    
    UI rinv;
    void gcd(LL a, LL b, LL& x, LL& y) {
    	if(!b){ x = 1; y = 0; return ; }
    	gcd(b, a % b, y, x); y -= (a / b) * x;
    	return ;
    }
    void getinv() {
    	LL x, y;
    	gcd(rate, 4294967296ll, x, y);
    	rinv = x;
    	return ;
    }
    
    short S[maxn<<1];
    int rpow[maxn], fr[2][2][maxn], ed[2][2][maxn]; // [rev][add]
    int hd[maxn], tl[maxn], ans[maxn], top;
    
    void getMore() {
    	if(ans[top] + 1 <= tl[top] - hd[top] + 1) {
    		ed[0][1][top] = ed[0][0][top] + rpow[ans[top]] * S[tl[top]-ans[top]];
    		ed[1][1][top] = ed[1][0][top] * rate + S[tl[top]-ans[top]];
    		fr[0][1][top] = fr[0][0][top] * rate + S[hd[top]+ans[top]];
    		fr[1][1][top] = fr[1][0][top] + rpow[ans[top]] * S[hd[top]+ans[top]];
    	}
    	else rep(rev, 0, 1) ed[rev][1][top] = fr[rev][1][top] = 0;
    	return ;
    }
    
    void addr(short c) {
    	top++;
    	S[tl[top] = tl[top-1]+1] = c;
    	hd[top] = hd[top-1];
    	if(ans[top-1] + 1 <= tl[top-1] - hd[top-1] + 1 && ed[0][1][top-1] * rate + c == ed[1][1][top-1] + rpow[ans[top-1]+1] * c) { // ans + 2
    		ans[top] = ans[top-1] + 2;
    		ed[0][0][top] = ed[0][1][top-1] * rate + c;
    		ed[1][0][top] = ed[1][1][top-1] + rpow[ans[top-1]+1] * c;
    		fr[0][0][top] = fr[0][1][top-1] * rate + S[hd[top-1]+ans[top-1]+1];
    		fr[1][0][top] = fr[1][1][top-1] + rpow[ans[top-1]+1] * S[hd[top-1]+ans[top-1]+1];
    	}
    	else if(ed[0][0][top-1] * rate + c == ed[1][0][top-1] + rpow[ans[top-1]] * c) { // ans + 1
    		ans[top] = ans[top-1] + 1;
    		ed[0][0][top] = ed[0][0][top-1] * rate + c;
    		ed[1][0][top] = ed[1][0][top-1] + rpow[ans[top-1]] * c;
    		fr[0][0][top] = fr[0][0][top-1] * rate + S[hd[top]+ans[top-1]];
    		fr[1][0][top] = fr[1][0][top-1] + rpow[ans[top-1]] * S[hd[top]+ans[top-1]];
    	}
    	else {
    		ans[top] = ans[top-1];
    		ed[0][0][top] = ed[0][0][top-1] * rate + c - rpow[ans[top]] * S[tl[top]-ans[top]];
    		ed[1][0][top] = (ed[1][0][top-1] + rpow[ans[top]] * c - S[tl[top]-ans[top]]) * rinv;
    		fr[0][0][top] = fr[0][0][top-1];
    		fr[1][0][top] = fr[1][0][top-1];
    	}
    	getMore();
    	return ;
    }
    
    void addl(short c) {
    	top++;
    	S[hd[top] = hd[top-1]-1] = c;
    	tl[top] = tl[top-1];
    	if(ans[top-1] + 1 <= tl[top-1] - hd[top-1] + 1 && fr[0][1][top-1] + rpow[ans[top-1]+1] * c == fr[1][1][top-1] * rate + c) { // ans + 2
    		ans[top] = ans[top-1] + 2;
    		fr[0][0][top] = fr[0][1][top-1] + rpow[ans[top-1]+1] * c;
    		fr[1][0][top] = fr[1][1][top-1] * rate + c;
    		ed[0][0][top] = ed[0][1][top-1] + rpow[ans[top-1]+1] * S[tl[top-1]-ans[top-1]-1];
    		ed[1][0][top] = ed[1][1][top-1] * rate + S[tl[top-1]-ans[top-1]-1];
    	}
    	else if(fr[0][0][top-1] + rpow[ans[top-1]] * c == fr[1][0][top-1] * rate + c) { // ans + 1
    		ans[top] = ans[top-1] + 1;
    		fr[0][0][top] = fr[0][0][top-1] + rpow[ans[top-1]] * c;
    		fr[1][0][top] = fr[1][0][top-1] * rate + c;
    		ed[0][0][top] = ed[0][0][top-1] + rpow[ans[top-1]] * S[tl[top]-ans[top-1]];
    		ed[1][0][top] = ed[1][0][top-1] * rate + S[tl[top]-ans[top-1]];
    	}
    	else {
    		ans[top] = ans[top-1];
    		fr[0][0][top] = (fr[0][0][top-1] + rpow[ans[top]] * c - S[hd[top]+ans[top]]) * rinv;
    		fr[1][0][top] = fr[1][0][top-1] * rate + c - rpow[ans[top]] * S[hd[top]+ans[top]];
    		ed[0][0][top] = ed[0][0][top-1];
    		ed[1][0][top] = ed[1][0][top-1];
    	}
    	getMore();
    	return ;
    }
    
    int main() {
    	getinv();
    	top = 1;
    	hd[1] = maxn; tl[1] = maxn - 1; ans[1] = 0;
    	rep(rev, 0, 1) rep(add, 0, 1) fr[rev][add][1] = ed[rev][add][1] = 0;
    	
    	int q = read(), lst = 0; char c = Getchar(); LL sans = 0;
    	rpow[0] = 1; rep(i, 1, q + 1) rpow[i] = rpow[i-1] * rate;
    	while(!isdigit(c)) c = Getchar();
    	rep(i, 1, q) {
    		short op = c - '0', x = 0;
    		c = Getchar(); x = c - '0'; c = Getchar(); x = x * 10 + c - '0'; if(i < q) c = Getchar();
    		x = (x + lst) % 100;
    		if(op == 1) addr(x);
    		if(op == 2) addl(x);
    		if(op == 3) top -= x;
    		lst = ans[top];
    		// printf("%d %d: %d
    ", op, x, lst);
    		sans += lst;
    	}
    	
    	printf("%lld
    ", sans);
    	
    	return 0;
    }
    

    [Problem C]Alice and Bob VII

    试题描述

    从前,有 (n) 个盒子(编号从 (1)(n)),(m) 把钥匙(编号从 (1)(m))和 (d) 个商店(编号从 (1)(d))。编号为 (i) 的钥匙可以打开编号为 (a_{i,1},a_{i,2},cdots,a_{i,k_i}) 的盒子。但是,一把钥匙一旦打开了一个盒子,它会立刻消失。因此,一把钥匙不能打开多个盒子。编号为 (i) 的钥匙只在商店 (s_i) 出售,价格为 (c_i)
    个金币。Alice 不能多次购买同一把钥匙。现在,Alice 想买一些钥匙来打开所有的盒子。

    Bob 想来捣乱。他可以在 Alice 决定购买钥匙之前改变某些钥匙的价格。如果 Bob 支付 (b_j) 个金币,Bob 就可以将商店 (j) 中所有钥匙的价格全部提高 (1) 金币。对于每家商店,他可以重复上述过程任意非负整数次。例如:如果他支付 (2b_j) 个金币,他可以将商店 (j) 中所有钥匙的价格全部提高 (2) 金币;但是,他不能支付 (frac{b_j}{2}) 个金币来将价格提高 (0.5) 金币。

    Alice 的目的是最小化 ((Alice支付的金币 - Bob支付的金币)),Bob 的目的是最大化该值。假设 Alice 和 Bob 都以最优策略来操作,请你计算最终该值是多少。

    如果该值为无穷大,输出 (-1)

    数据保证如果 Bob 不来捣乱,Alice 是可以打开所有盒子的。

    输入

    第一行三个整数 (n,m,d(1 le n le 100,1 le m le 1000,1 le n,d le m))

    接下来 (m) 行,每行表示一把钥匙。每行开头有三个整数 (c_i,s_i,k_i) ,分别表示钥匙价格,钥匙出售商店的编号,这把钥匙能打开多少个盒子。接下来 (k_i) 个整数,表示这把钥匙能打开的盒子的编号。((1 le c_i le 1000,1 le s_i le d,1 le k_i le mathrm{min}(10,n),1 le a_i,j le n, and if j e k,a_{i,j} e a_{i,k}))

    接下来 (d) 行,每行一个整数 (b_i(1 le b_i le 1000))

    输出

    输出一个整数表示答案。

    输入示例1

    3 4 1
    2 1 2 1 2
    2 1 2 2 3
    2 1 2 3 1
    3 1 3 1 2 3
    5
    

    输出示例1

    6
    

    输入示例2

    3 4 1
    2 1 2 1 2
    2 1 2 2 3
    2 1 2 3 1
    3 1 3 1 2 3
    2
    

    输出示例2

    -1
    

    输入示例2

    2 3 2
    3 1 2 1 2
    4 1 1 2
    5 2 2 1 2
    1
    2
    

    输出示例2

    8
    

    数据规模及约定

    对于 (30\%) 的数据,(1 le n le 5, 1 le m le 10)

    对于所有数据,(1 le n le 100, 1 le m le 1000, 1 le n,d le m)

    题解

    这是一道处于未知领域的题……要用到拉格朗日乘数法证明它的正确性,但是仔细想一想发现还是证明不了,把原题解丢在这里吧,作为一个未解问题。(或许这题彻头彻尾地错了呢?)

    T_T

    拉格朗日乘数法和KKT条件

    支持向量机:Duality

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    #include <vector>
    using namespace std;
    #define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
    #define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; i--)
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 2110
    #define maxm 24210
    #define oo 2147483647
    
    struct Edge {
    	int from, to, flow, cost;
    	Edge() {}
    	Edge(int _1, int _2, int _3, int _4): from(_1), to(_2), flow(_3), cost(_4) {}
    } es[maxm];
    struct ZKW {
    	int n, m, s, t, cost, ans, head[maxn], nxt[maxm];
    	Edge es[maxm];
    	int d[maxn], Q[maxn], hd, tl;
    	bool inq[maxn];
    	bool vis[maxn];
    	
    	void init() {
    		m = 0; memset(head, -1, sizeof(head));
    		return ;
    	}
    	void setn(int _) {
    		n = _;
    		return ;
    	}
    	
    	void AddEdge(int a, int b, int c, int d) {
    		es[m] = Edge(a, b, c, d); nxt[m] = head[a]; head[a] = m++;
    		es[m] = Edge(b, a, 0, -d); nxt[m] = head[b]; head[b] = m++;
    		return ;
    	}
    	
    	int Nxt(int x) { return (x + 1) % maxn; }
    	bool BFS() {
    		rep(i, 1, n) d[i] = oo;
    		d[t] = 0;
    		hd = tl = 0; Q[tl = Nxt(tl)] = t; inq[t] = 1;
    		while(hd != tl) {
    			int u = Q[hd = Nxt(hd)]; inq[u] = 0;
    			for(int i = head[u]; i != -1; i = nxt[i]) {
    				Edge& e = es[i^1];
    				if(e.flow && d[e.from] > d[u] + e.cost) {
    					d[e.from] = d[u] + e.cost;
    					if(!inq[e.from]) inq[e.from] = 1, Q[tl = Nxt(tl)] = e.from;
    				}
    			}
    		}
    		if(d[s] == oo) return 0;
    		cost = d[s];
    		return 1;
    	}
    	
    	int DFS(int u, int a) {
    		if(u == t || !a) return ans += cost * a, a;
    		if(vis[u]) return 0;
    		vis[u] = 1;
    		int flow = 0, f;
    		for(int i = head[u]; i != -1; i = nxt[i]) {
    			Edge& e = es[i];
    			if(d[e.to] == d[u] - e.cost && (f = DFS(e.to, min(a, e.flow)))) {
    				flow += f; a -= f;
    				e.flow -= f; es[i^1].flow += f;
    				if(!a) return flow;
    			}
    		}
    		return flow;
    	}
    	
    	int MaxFlow(int _s, int _t) {
    		s = _s; t = _t;
    		int flow = 0, f;
    		while(BFS())
    			do {
    				memset(vis, 0, sizeof(vis));
    				f = DFS(s, oo);
    				flow += f;
    			} while(f);
    		return flow;
    	}
    } sol;
    
    int CntP;
    struct Point {
    	int id;
    	Point(): id(0) {}
    	int p() { return id ? id : id = ++CntP; }
    } box[maxn], key[maxn], shop[maxn], S, T;
    vector <int> idm[maxn];
    int addcost[maxn];
    
    int main() {
    	int bx = read(), ky = read(), shp = read();
    	sol.init();
    	rep(i, 1, ky) {
    		int pri = read(), sid = read(), k = read();
    		idm[sid].push_back(sol.m);
    		sol.AddEdge(shop[sid].p(), key[i].p(), 1, pri);
    		rep(j, 1, k) sol.AddEdge(key[i].p(), box[read()].p(), 1, 0);
    	}
    	rep(i, 1, shp) sol.AddEdge(S.p(), shop[i].p(), addcost[i] = read(), 0);
    	rep(i, 1, bx) sol.AddEdge(box[i].p(), T.p(), 1, 0);
    	sol.setn(CntP);
    	
    	if(sol.MaxFlow(S.p(), T.p()) < bx) return puts("-1"), 0;
    	printf("%d
    ", sol.ans);
    	
    	return 0;
    }
    
  • 相关阅读:
    图解AI数学基础 | 从入门到精通 系列教程
    设置开机启动项,开机自动启动文件夹在哪里?
    vbs创建目录,可循环创建父级目录
    像玩游戏一样学Git命令
    技术管理进阶——谁能成为Leader,大Leader该做什么
    python测试框架Pytest 系列文章
    VBA下载文件三种方法
    Linux系统『学了就忘』 系列文章
    Echarts Y轴保留几位小数
    redis怎么清除缓存
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/8313306.html
Copyright © 2020-2023  润新知