zoukankan      html  css  js  c++  java
  • AHOI2018 Day1

    以前写过一份 Day2 的。

    这套题难度很大。当年赛场上貌似得分率不高。

    寻宝游戏

    (vee)(land) 看成 0/1,与原序列对比发现变成答案中的 0/1 等价于比较数字的大小。最后排序即可。

    #include <bits/stdc++.h>
    using std::sort;
    const int N = 1005, M = 5005, P = 1e9 + 7;
    int n, m, Q, a[M][N], l[M]; char ch[M];
    bool cmp(int x, int y) {
    	for (int i = n; i; i--)
    		if (a[x][i] != a[y][i]) return a[x][i] < a[y][i];
    	return 0;
    }
    int main() {
    	scanf("%d%d%d", &n, &m, &Q);
    	for (int i = 1; i <= n; i++) {
    		scanf("%s", ch+1);
    		for (int j = 1; j <= m; j++)
    			a[j][i] = ch[j]-'0';
    	}
    	for (int i = 1; i <= m; i++) l[i] = i;
    	sort(l+1, l+m+1, cmp);
    	while (Q--) {
    		int x = 0, y = 0, ok = 1;
    		scanf("%s", ch+1);
    		for (int i = 1; i <= m; i++) {
    			if (ch[l[i]] == '1' && !x) x = i;
    			if (ch[l[i]] == '0') y = i;
    		}
    		if (x) for (int i = n; i; i--)
    			if (a[l[x]][i] != a[l[y]][i]) { 
    				if (a[l[x]][i] < a[l[y]][i]) ok = 0;
    				break;
    			}
    		if (!ok) puts("0");
    		else {
    			int ans = x?0:1;
    			for (int i = n; i; i--)
    				ans = ((2*ans+a[l[x]][i]-a[l[y]][i])%P + P)%P;
    			printf("%d
    ", ans);
    		}
    	}
    	return 0;
    }
    

    转盘

    两处缩放:第一处在选取解时,我们把选取每个物品的时间在总时间不变的情况下尽可能推迟。发现当一个递增序列的值处处大于时间则递增序列最大值即为答案。

    第二处在于发现上述问题的性质,破环成链再对下标差分后,求 每个长度为 (n) 的区间最大值+一个与下标相关的偏移量 前面这个整体的 最小值。分析发现可以进一步把区间长度放到后缀长度。这一点很重要。

    后缀max递减,最后发现实际上就是一个楼房重建问题。复杂度 (mathcal O(nlog^2 n))

    #include <bits/stdc++.h>
    using std::max;
    using std::min;
    const int N = 100005;
    int n, m, p, las;
    #define lc (o << 1)
    #define rc (o << 1 | 1)
    int ma[N*4], val[N*4], fix[N*4];
    int query(int o, int l, int r, int v) {
    	if (l == r) return v < ma[o] ? val[o] : v+l;
    	int mid = l+r>>1;
    	return v > ma[rc] ? min(query(lc, l, mid, v), v+mid+1) : min(fix[o], query(rc, mid+1, r, v));
    }
    void pushup(int o, int l, int r) {
    	int mid = l+r>>1;
    	ma[o] = max(ma[lc], ma[rc]);
    	val[o] = min(val[rc], fix[o] = query(lc, l, mid, ma[rc]));
    }
    void modify(int o, int l, int r, int p, int v) {
    	if (l == r) { ma[o] = v; val[o] = v+p; return; }
    	int mid = l+r>>1;
    	p <= mid ? modify(lc, l, mid, p, v) : modify(rc, mid+1, r, p, v);
    	pushup(o, l, r);
    }
    int main() {
    	scanf("%d%d%d", &n, &m, &p);
    	for (int i = 1; i <= n; i++) { int x; scanf("%d", &x), modify(1, 1, n, i, x-i); }
    	printf("%d
    ", las = query(1, 1, n, ma[1]-n) + n - 1);
    	while (m--) {
    		int x, y; scanf("%d%d", &x, &y); p && (x ^= las, y ^= las);
    		modify(1, 1, n, x, y-x);
    		printf("%d
    ", las = query(1, 1, n, ma[1]-n) + n - 1);
    	}
    	return 0;
    }
    

    毒瘤

    合理删去 (n-m+1) 条边后是一棵树。这样子做 DP 还需要关心去掉的 (n-m+1) 对限制。

    枚举这些限制,总方案数为 (3 imes 2^{n-m+1}=mathcal O(2^{n-m+1}))。给上限制再做 DP 每次都要 (mathcal O(n)) 的复杂度,太屑了。

    考虑优化,注意到 DP 实际上只跟这些点构成的虚树有关。然后就可以类似 NOIP2018 的 D2T3 一样搞,只不过这里不用倍增。仍然要注意维护 DP 值的顺序。

    总复杂度 (mathcal O(n + s2^s)),这里 (s=n-m+1)

    #include <bits/stdc++.h>
    using std::vector;
    const int N = 100020, P = 998244353;
    int n, m, ans = 0;
    struct Edge {
    	int v, nxt;
    } e[N*2];
    int edges = 0, G[N];
    void adde(int u, int v) {
    	e[edges++] = (Edge){v, G[u]}, G[u] = edges-1;
    }
    int fa[N];
    int fset(int x) { return fa[x] == x ? x : fa[x] = fset(fa[x]); }
    void merge(int x, int y) { fa[fset(x)] = fset(y); }
    int tag[N], f[N][2], g[N][2][2];
    vector<int> e2[N], l;
    int dfs1(int u, int fa) {
    	f[u][0] = f[u][1] = 1;
    	for (int i = G[u], v; ~i; i = e[i].nxt) {
    		if (v = e[i].v, v == fa) continue;
    		int t = dfs1(v, u);
    		f[u][0] = 1LL * f[u][0] * (f[v][0] + f[v][1]) % P;
    		f[u][1] = 1LL * f[u][1] * f[v][0] % P;
    		if (t) e2[u].push_back(t);
    	}
    	if (!tag[u]) tag[u] = e2[u].size() > 1 ? u : e2[u].size() ? e2[u][0] : 0;
    	return tag[u];
    }
    void dfs2(int u, int fa) {
    	for (int i = G[u], v; ~i; i = e[i].nxt) {
    		if (v = e[i].v, v == fa) continue;
    		dfs2(v, u); int x = tag[v];
    		if (!x) continue;
    		g[x][0][0] = (g[x][0][0] + g[x][0][1]) % P, g[x][0][1] = (g[x][0][0] + P - g[x][0][1]) % P;
    		g[x][1][0] = (g[x][1][0] + g[x][1][1]) % P, g[x][1][1] = (g[x][1][0] + P - g[x][1][1]) % P;
    	}
    	g[u][0][0] = g[u][1][1] = 1;
    	for (int i = G[u], v; ~i; i = e[i].nxt) {
    		if (v = e[i].v, v == fa || tag[v]) continue;
    		int x = tag[u];
    		g[x][0][0] = 1LL * g[x][0][0] * (f[v][0] + f[v][1]) % P;
    		g[x][0][1] = 1LL * g[x][0][1] * f[v][0] % P;
    		g[x][1][0] = 1LL * g[x][1][0] * (f[v][0] + f[v][1]) % P;
    		g[x][1][1] = 1LL * g[x][1][1] * f[v][0] % P;
    	}
    }
    int dp[N][2], col[N];
    void calc(int u) {
    	dp[u][0] = dp[u][1] = 1;
    	if (~col[u]) dp[u][col[u]^1] = 0;
    	for (int i = 0, v; i < e2[u].size(); i++) {
    		v = e2[u][i]; calc(v);
    		dp[u][0] = 1LL * dp[u][0] * ((1LL * dp[v][0] * g[v][0][0] + 1LL * dp[v][1] * g[v][1][0]) % P) % P;
    		dp[u][1] = 1LL * dp[u][1] * ((1LL * dp[v][0] * g[v][0][1] + 1LL * dp[v][1] * g[v][1][1]) % P) % P;
    	}
    }
    int main() {
    	scanf("%d%d", &n, &m);
    	memset(G, -1, sizeof G);
    	for (int i = 1; i <= n; i++) fa[i] = i;
    	for (int i = 1; i <= m; i++) {
    		int u, v; scanf("%d%d", &u, &v);
    		if (fset(u) == fset(v)) l.push_back(u), l.push_back(v), tag[u] = u, tag[v] = v;
    		else adde(u, v), adde(v, u), merge(u, v);
    	}
    	tag[1] = 1; dfs1(1, 0); dfs2(1, 0);
    	memset(col, -1, sizeof col);
    	for (int S = 0; S < 1<<(m-n+1)*2; S++) { // 这里不小心写成了2^2s的枚举,不过人没事
    		for (int i = 0; i < (m-n+1)*2; i++) col[l[i]] = -1;
    		int ok = 1;
    		for (int i = 0; i < (m-n+1)*2; i++) {
    			if (~col[l[i]] && col[l[i]] != (S >> i & 1)) { ok = 0; break; }
    			col[l[i]] = S >> i & 1;
    		}
    		for (int i = 0; i < (m-n+1)*2; i += 2)
    			if (col[l[i]] && col[l[i+1]]) { ok = 0; break; }
    		if (!ok) continue;
    		calc(1);
    		ans = (ans + 1LL * dp[1][0] * g[1][0][0] + 1LL * dp[1][1] * g[1][1][1]) % P;
    	}
    	printf("%d", ans);
    	return 0;
    }
    
  • 相关阅读:
    机器学习-分类简单介绍
    状态压缩动态规划 -- 旅行商问题
    30 天学习 30 种新技术系列
    Sublime Text3 高亮显示Jade语法 (Windows 环境)
    程序启动缓慢-原来是hbm.xml doctype的原因
    Spring4 Hibernate4 Struts2在WebLogic 10.3.3上面部署
    Spring的 classpath 通配符加载配置文件
    nmp install 异常
    cvc-complex-type.2.4.c: The matching wildcard...
    LazyInitializationException--由于session关闭引发的异常
  • 原文地址:https://www.cnblogs.com/ac-evil/p/14324654.html
Copyright © 2011-2022 走看看