• 2019.12.30考试总结


    T1摆棋子
    看到这么多的限制,第一直觉就是网络流,最小费用最大流不能做,因为把棋子代价看成1后最大流的条件并不好满足。
    注意到每一行每一列都有一个最小限制,对应到网络流上就是流的下界,整体跑一个有下界的最小流就可以了。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #define LL long long
    #define DB double
    using namespace std;
    int n, m, k, x, y, tot = 1, S, T, SS, TT, ans, flow;
    const int N = 105, inf = 1 << 30;
    int X[N], Y[N], vis[N][N], d[N * N], A[N * N];
    int head[N * N];
    struct bian 
    {
    	int to, nt, cap;
    } e[N * N * 4];
    void add(int f, int t, int c) 
    {
    	e[++tot] = (bian) {t, head[f], c};
    	head[f] = tot;
    }
    void ADD(int f, int t, int c) 
    {
    	add(f, t, c); add(t, f, 0);
    }
    inline int read() 
    {
    	int res = 0; char ch = getchar(); bool XX = false;
    	for (; !isdigit(ch); ch = getchar())(ch == '-') && (XX = true);
    	for (; isdigit(ch); ch = getchar())res = (res << 3) + (res << 1) + (ch ^ 48);
    	return XX ? -res : res;
    }
    queue<int>q;
    int bfs(int S, int T) 
    {
    	int x;
    	memset(d, 0, sizeof(d));
    	while (!q.empty())q.pop();
    	q.push(S); d[S] = 1;
    	while (!q.empty()) 
    	{
    		x = q.front(); q.pop();
    		for (int i = head[x]; i; i = e[i].nt)
    			if (e[i].cap && !d[e[i].to]) 
    			{
    				d[e[i].to] = d[x] + 1;
    				q.push(e[i].to);
    				if (e[i].to == T)return 1;
    			}
    	}
    	return 0;
    }
    int dinic(int x, int flow, int T) 
    {
    	if (x == T || !flow)return flow;
    	int res = flow, k;
    	for (int i = head[x]; i; i = e[i].nt)
    		if (e[i].cap && d[e[i].to] == d[x] + 1) 
    		{
    			k = dinic(e[i].to, min(e[i].cap, res), T);
    			if (!k)d[e[i].to] = 0;
    			e[i].cap -= k; e[i ^ 1].cap += k;
    			res -= k;
    		}
    	return flow - res;
    }
    bool pan() 
    {
    	int js;
    	for (int i = 1; i <= n; ++i) 
    	{
    		js = 0;
    		for (int j = 1; j <= m; ++j)
    			if (!vis[i][j])++js;
    		if (js < X[i])return 1;
    	}
    	for (int j = 1; j <= m; ++j) 
    	{
    		js = 0;
    		for (int i = 1; i <= n; ++i)
    			if (!vis[i][j])++js;
    		if (js < Y[j])return 1;
    	}
    	return 0;
    }
    int main() 
    {
    	freopen("chessman.in", "r", stdin);
    	freopen("chessman.out", "w", stdout);
    	cin >> n >> m >> k; S = n + m + 1, T = n + m + 2, SS = n + m + 3, TT = n + m + 4;
    	for (int i = 1; i <= n; ++i)X[i] = read();
    	for (int i = 1; i <= m; ++i)Y[i] = read();
    	for (int i = 1; i <= k; ++i) 
    	{
    		x = read(); y = read();
    		vis[x][y] = 1;
    	}
    	if (pan()) 
    	{
    		puts("No Solution");
    		fclose(stdin); fclose(stdout);
    		return 0;
    	}
    	for (int i = 1; i <= n; ++i) 
    	{
    		ADD(S, i, inf - X[i]);
    		A[S] -= X[i]; A[i] += X[i];
    	}
    	for (int i = 1; i <= m; ++i) 
    	{
    		ADD(n + i, T, inf - Y[i]);
    		A[n + i] -= Y[i]; A[T] += Y[i];
    	}
    	for (int i = 1; i <= n; ++i)
    		for (int j = 1; j <= m; ++j)
    			if (!vis[i][j])ADD(i, n + j, 1);
    	for (int i = 1; i <= n + m + 2; ++i)
    		if (A[i] > 0) {ADD(SS, i, A[i]);}
    		else if (A[i])ADD(i, TT, -A[i]);
    	while (bfs(SS, TT))while (flow = dinic(SS, inf, TT))ans += flow;
    	ADD(T, S, inf);
    	while (bfs(SS, TT))while (flow = dinic(SS, inf, TT))ans += flow;
    	cout << e[tot].cap;
    	fclose(stdin); fclose(stdout);
    	return 0;
    }
    

    T2旅行路线
    把度数看成一个字符,就变成了树上的不同子串个数问题。
    一个序列的我们能解决,放到树上只需要把last改成fa的id就行了。

    #include<iostream>
    #include<cstdio>
    #include<set>
    #include<map>
    #define LL long long
    #define DB double
    using namespace std;
    int n, tot, x, y, cnt;
    const int N = 1000010;
    int head[N], du[N], id[N], len[N], fa[N];
    map<int, int>tr[N];
    struct bian {int to, nt;} e[N];
    LL ans;
    void add(int f, int t) 
    {
    	e[++tot] = (bian) {t, head[f]};
    	head[f] = tot;
    }
    inline int read() 
    {
    	int res = 0; char ch = getchar(); bool XX = false;
    	for (; !isdigit(ch); ch = getchar())(ch == '-') && (XX = true);
    	for (; isdigit(ch); ch = getchar())res = (res << 3) + (res << 1) + (ch ^ 48);
    	return XX ? -res : res;
    }
    void Insert(int x, int Q, int las) 
    {
    	int np = ++cnt, p = las, q, nq;
    	len[np] = len[p] + 1; id[Q] = cnt;
    	for (; p && tr[p].find(x) == tr[p].end(); p = fa[p])tr[p][x] = np;
    	if (!p)fa[np] = 1;
    	else if (len[q = tr[p][x]] == len[p] + 1)fa[np] = q;
    	else 
    	{
    		len[nq = ++cnt] = len[p] + 1;
    		fa[nq] = fa[q]; fa[q] = fa[np] = nq; tr[nq] = tr[q];
    		for (; p; p = fa[p]) 
    		{
    			if (tr[p].find(x) == tr[p].end() || tr[p][x] != q)break;
    			tr[p][x] = nq;
    		}
    	}
    }
    void dfs(int x, int fa) 
    {
    	Insert(du[x], x, id[fa]);
    	for (int i = head[x]; i; i = e[i].nt)
    		if (e[i].to != fa)dfs(e[i].to, x);
    }
    int main() 
    {
    	freopen("route.in", "r", stdin);
    	freopen("route.out", "w", stdout);
    	cnt = id[0] = 1; cin >> n;
    	for (int i = 1; i < n; ++i) 
    	{
    		x = read(); y = read();
    		add(y, x); du[x]++; du[y]++;
    	}
    	dfs(1, 0);
    	for (int i = 2; i <= cnt; ++i)ans += len[i] - len[fa[i]];
    	cout << ans;
    	fclose(stdin); fclose(stdout);
    	return 0;
    }
    

    T3流浪者
    总的方案数就是(C_{n+m-2}^{n-1}),因为体力减小的快,只有log种取值,所以总的体力是对每一种s乘上相应的方案数的和。
    f[i][j] 表示从起点出发经过恰好 j 个特殊点到达第 i 个障碍点的方案,依然考虑容斥,枚举不合法路径上除 i 之外的第 j 个特殊点
    (displaystyle f[i][j]=C_{x_i+y_i}^{x_i} - sum_{k=1}^{i-1}f[k][j]·ways(k, i) - sum_{k=1}^{j-1}f[i][k])
    ways(i, j) 表示从第 i 个特殊点到第 j 个障碍点的方案
    不懂的话可以吧右边的减号移到左边来。

    #include<algorithm>
    #include<iostream>
    #include<cstdio>
    #define int long long
    #define LL long long
    #define DB double
    using namespace std;
    int n, m, k, s, x, y, mx;
    const int mod = 1e9 + 7, N = 200010, M = 2005;
    int ex[M];
    LL jc[N], inv[N], f[M][M], w[M][M], sum[M][M];
    LL ans;
    inline int read() 
    {
    	int res = 0; char ch = getchar(); bool XX = false;
    	for (; !isdigit(ch); ch = getchar())(ch == '-') && (XX = true);
    	for (; isdigit(ch); ch = getchar())res = (res << 3) + (res << 1) + (ch ^ 48);
    	return XX ? -res : res;
    }
    struct dian 
    {
    	int x, y;
    	friend bool operator <(const dian &a, const dian &b) {return a.x + a.y < b.x + b.y;}
    } p[M];
    LL ksm(LL a, LL b, LL mod) 
    {
    	LL res = 1;
    	for (; b; b >>= 1, a = a * a % mod)
    		if (b & 1)res = res * a % mod;
    	return res;
    }
    void YYCH() 
    {
    	jc[0] = jc[1] = inv[0] = inv[1] = 1;
    	for (int i = 2; i <= n + m; ++i)jc[i] = jc[i - 1] * i % mod;
    	inv[n + m] = ksm(jc[n + m], mod - 2, mod);
    	for (int i = n + m - 1; i >= 1; --i)inv[i] = inv[i + 1] * (i + 1) % mod;
    }
    LL C(LL n, LL m) 
    {
    	if (n < m || n < 0 || m < 0)return 0;
    	return jc[n] * inv[m] % mod * inv[n - m] % mod;
    }
    inline LL ni(LL x) {return ksm(x, mod - 2, mod);}
    signed main() 
    {
    	freopen("rover.in", "r", stdin);
    	freopen("rover.out", "w", stdout);
    	cin >> n >> m >> k >> s;
    	YYCH();
    	for (int i = 1; i <= k; ++i)
    		p[i].x = read(), p[i].y = read();
    	p[0] = (dian) {1, 1}; p[++k] = (dian) {n, m};
    	sort(p, p + k + 1); ex[0] = s;
    	for (int i = 1; i <= 20; ++i) 
    	{
    		ex[i] = (ex[i - 1] + 1) >> 1;
    		if (ex[i] == 1 && !mx)mx = i;
    	}
    	f[0][0] = 1;
    	for (int i = 0; i <= k; ++i)
    		for (int j = 0; j < i; ++j)
    			w[i][j] = C(p[i].x - p[j].x + p[i].y - p[j].y, p[i].x - p[j].x);
    	for (int i = 1; i <= k; ++i)
    		for (int j = 0; j <= mx + 1; ++j) 
    		{
    			f[i][j] = C(p[i].x + p[i].y - 2, p[i].x - 1);
    			if (j)f[i][j] = (f[i][j] - sum[i][j - 1] + mod) % mod;
    			for (int l = 0; l < i; ++l)
    				f[i][j] = (f[i][j] - f[l][j] * w[i][l] % mod + mod) % mod;
    			if (j)sum[i][j] = (sum[i][j - 1] + f[i][j]) % mod;
    			else sum[i][j] = f[i][j];
    		}
    	for (int i = 1; i <= mx; ++i)
    		(ans += f[k][i] * ni(C(n + m - 2, n - 1)) % mod * ex[i - 1] % mod) %= mod;
    	ans = (ans + (C(n + m - 2, n - 1) - sum[k][mx] + mod) % mod * ni(C(n + m - 2, n - 1)) % mod) % mod;
    	cout << ans;
    	fclose(stdin); fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    servlet容器与web容器的概念
    apache点NET环境
    JAVA web选型
    Web服务器排行:Nginx超越Apache 成为全球
    软件介绍(apache lighttpd nginx)
    C++性能榨汁机之虚函数的开销
    C++性能榨汁机之伪共享
    《四重缘起深般若》 和 《心经修正圆通法门》
    冥想方法
    中医方子
  • 原文地址:https://www.cnblogs.com/wljss/p/12121561.html
Copyright © 2020-2023  润新知