7_22 模拟赛

jpg

T1

解题思路

这道题手玩样例后就有了大致的感觉,如果倒推一定是 \(0\) 内部自行解决自己合并,而其他的数都减一,正确性可以稍微感性理解一下,首先往下减少一定是希望一次性减得越多越好,因为总和一定,最后目标和为 \(0\),所以有其他的数都大力减少的想法,而如果有一些数变成了 \(0\),我们其实并不急着合并,因为让别的数减少,出现新的 \(0\) 再去合并结果起码不会更劣,只是改了合并时间而已,故考虑有 \(0\) 内部解决,其他数全部变小。

Code:

#include <algorithm>
#include <cstdio>

using namespace std;

const int N = 1000010;

int n;
int cnt[N];
int ans;

int main() {
    scanf("%d", &n);
    for (int i = 1, tmp; i <= n; i++) {
        scanf("%d", &tmp);
        cnt[tmp]++;
    }
    int ct = 0;
    int tmpnum = cnt[ct];
    while (n > 1) {
        ans++;
        n -= tmpnum >> 1;
        tmpnum = (tmpnum + 1) >> 1;
        tmpnum += cnt[++ct];
    }
    printf("%d\n", ans);
    return 0;
}

因为自己没有写所以贺了 \(\rm amr2020\) 神仙的代码。

T2

解题思路:

注意到天数达到 \(1000\) 时代价很高,此时代价不小于所得,所以可以暴力枚举天数来做,设 f[t][i] 表示第 \(t\) 天恰到 \(j\) 的最长路,求答案时暴力枚举第几天更新 ans 即可。

Code:

#include<bits/stdc++.h>
using namespace std;
const int N=1008,M=2008,T=1005;
int n,m,c;
int moy[N];
int h[N],cnt=0;
struct edg{
    int to,nxt;
}e[M];
int f[N][T],ans;
void add(int u,int v){
    e[++cnt]=(edg){v,h[u]};
    h[u]=cnt;
}
int main(){
    memset(f,-1,sizeof(f));
    scanf("%d%d%d",&n,&m,&c);
    for(int i=1;i<=n;i++){
        scanf("%d",&moy[i]);
    }
    for(int x,y,i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    f[1][0]=0;
    for(int t=1;t<=1000;t++){
        for(int i=1;i<=n;i++){
            if(f[i][t-1]==-1)continue;
            for(int p=h[i];p;p=e[p].nxt){
                int to=e[p].to;
                f[to][t]=max(f[i][t-1]+moy[to],f[to][t]);
            }
        }
    }
    for(int i=1;i<=1000;i++){
        ans=max(ans,f[1][i]-c*i*i);
    }
    printf("%d\n",ans);
    return 0;
}

T3

解题思路:

比较平凡的思路,设 \(s[r][l]\) 表示强制右端点为 \(r\) 左端点在 \(l \to r\) 范围内的答案和,那么求答案暴力枚举就行了,\(\cal O \rm(qn)\) 可以通过本题,更好的,离线后珂以做到 \(\cal O \rm(n^2)\),珂以通过。

Code:

#include <bits/stdc++.h>

using i64 = long long;
constexpr int inf = 1e9;

struct Ques {
	int l, r, id;
};

signed main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);

	int n, q;
	std::cin >> n >> q;

	int mx = -inf, mi = inf;
	std::vector<int> a(n + 1);
	for (int i = 1; i <= n; ++i) 
		std::cin >> a[i], mx = std::max(mx, a[i]), mi = std::min(mi, a[i]);

	for (int i = 1; i <= n; ++i) 
		a[i] -= mi;

	std::vector<std::vector<i64>> s(n + 1, std::vector<i64>(n + 1, 0));
	std::vector<int> buc(mx - mi + 1);

	for (int r = 3; r <= n; ++r) {
		i64 now = 0;
		for (int l = r - 1; l >= 1; --l) {
			if (3 * mi + a[l] + a[r] <= 0 && 3 * mi + a[l] + a[r] >= -mx + mi) {
				now += buc[-(3 * mi + a[l] + a[r])];
			}
			s[r][l] = now;
			++buc[a[l]];
		}
		for (int l = r - 1; l >= 1; --l) 
			--buc[a[l]];
	}

	std::vector<Ques> qs(q + 1);
	for (int i = 1; i <= q; ++i) {
		int a, b;
		std::cin >> a >> b;
		qs[i] = {a, b, i};
	}

	std::sort(qs.begin() + 1, qs.begin() + q + 1, [](Ques a, Ques b) {
		if (a.l != b.l) 
			return a.l < b.l;
		return a.r < b.r;
	});
	std::vector<i64> ans(q + 1);

	for (int i = 1; i <= q;) {
		int j = i;
		while (j <= q && qs[i].l == qs[j].l) 
			++j;
		int r = qs[i].l + 1;
		i64 res = 0;
		for (int k = i; k < j; ++k) {
			while (r < qs[k].r) {
				++r;
				res += s[r][qs[i].l];
			}
			ans[qs[k].id] = res;
		}
		i = j;
	}

	for (int i = 1; i <= q; ++i) 
		std::cout << ans[i] << '\n';
}

T4

解题思路:

二维偏序限制下的的转移,将跳板拆为起点和终点后可以用树状数组来做,也可以 cdq 分治处理。

Code:

#include <bits/stdc++.h>

struct Bit {
	int n;
	std::vector<int> c;

	Bit(int n) : c(n + 1, 0), n(n) {}
	inline void add(int p, int v) {
		while (p <= n) 
			c[p] = std::max(c[p], v), p += p & -p;
	}

	inline int qry(int p) {
		int res = 0;
		while (p) 
			res = std::max(res, c[p]), p -= p & -p;
		return res;
	}
};

signed main() {
	// freopen("1.in", "r", stdin);

	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);

	int n, p;
	std::cin >> n >> p;
	int sum = n + n;
	++n;

	struct Point { int x, y, ty, id; };

	std::vector<int> disc;
	std::vector<Point> a;
	a.push_back({1, 1, 1, 0});
	disc.push_back(1);

	std::vector<int> len(p + 1);
	for (int i = 1; i <= p; ++i) {
		int x1, y1, x2, y2;
		std::cin >> x1 >> y1 >> x2 >> y2;
		++x1, ++y1, ++x2, ++y2;
		len[i] = x2 - x1 + y2 - y1;
		a.push_back({x1, y1, 0, i});
		a.push_back({x2, y2, 1, i});

		disc.push_back(y1), disc.push_back(y2);
	}
	a.push_back({n, n, 2, p + 1});
	disc.push_back(n);

	std::sort(disc.begin(), disc.end());
	int l = std::unique(disc.begin(), disc.end()) - disc.begin();

	for (auto &it : a) {
		int val = it.y;
		it.y = std::lower_bound(disc.begin(), disc.begin() + l, val) - disc.begin() + 1;
	}
	
	std::sort(a.begin(), a.end(), [&](Point a, Point b) {
		if (a.x != b.x) return a.x < b.x;
		if (a.y != b.y) return a.y < b.y;
		return a.id < b.id;
	});

	std::vector<int> f(p + 2, 0);
	Bit b(l);

	for (auto it : a) {
		if (!it.ty) {
			assert(it.y <= l);
			int res = b.qry(it.y);
			f[it.id] = std::max(f[it.id], res + len[it.id]);
		}
		else if (it.ty == 1) {
			assert(it.y >= 1);
			b.add(it.y, f[it.id]);
		}
		else if (it.ty == 2) {
			int res = b.qry(it.y);
			std::cout << sum - res << '\n';
			exit(0);
		}
	}
}

T5

解题思路:

由于区间取反难以处理考虑差分,差分后的结果数组是容易求出的,而修改可以理解为平移,那么处理出每个点平移到别的地方的代价,状压 dp 即可。

Code:

// Problem: #520. 密码
// Contest: UOJ
// URL: https://sjzezoj.com/problem/520
// Memory Limit: 1024 MB
// Time Limit: 1000 ms
// Author: Railgun
// Start Time: 2021-07-22 17:05:28

#include <bits/stdc++.h>

constexpr int inf = 2e9;

signed main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);

	int n, k, m;
	std::cin >> n >> k >> m;
	++n;

	std::vector<int> vis(n);

	for (int i = 0; i < k; ++i) {
		int w;
		std::cin >> w;
		--w;
		vis[w] ^= 1, vis[w + 1] ^= 1;
	}

	std::vector<int> stk;
	for (int i = 0; i < n; ++i) {
		if (vis[i]) 
			stk.emplace_back(i);
	}

	std::vector<int> len(m);
	for (int i = 0; i < m; ++i) 
		std::cin >> len[i];

	std::vector<std::vector<int>> dist(stk.size(), std::vector<int>(stk.size(), inf));

	auto bfs = [&](int s) {
		std::vector<int> dis(n, inf);
		dis[stk[s]] = 0;

		std::queue<int> q;
		q.push(stk[s]);

		while (q.size()) {
			int x = q.front();
			q.pop();

			for (auto it : len) {
				if (x - it >= 0 && dis[x - it] > dis[x] + 1) 
					dis[x - it] = dis[x] + 1, q.push(x - it);
				if (x + it < n && dis[x + it] > dis[x] + 1) 
					dis[x + it] = dis[x] + 1, q.push(x + it);
			}
		}
		for (int i = 0; i < stk.size(); ++i) 
			dist[s][i] = dis[stk[i]];
	};

	for (int i = 0; i < stk.size(); ++i) 
		bfs(i);

	std::vector<int> dp(1 << stk.size(), inf);
	dp[0] = 0;
	for (int s = 0; s < (1 << stk.size()); ++s) {
		if (dp[s] == inf) 
			continue;
		for (int i = 0; i < stk.size(); ++i) {
			if (!((s >> i) & 1)) {
				for (int j = i + 1; j < stk.size(); ++j) {
					if (!((s >> j) & 1)) {
						int t = s ^ (1 << i) ^ (1 << j);
						dp[t] = std::min(dp[t], dp[s] + dist[i][j]);
					}
				}
			}
		}
	}

	if (dp[(1 << stk.size()) - 1] == inf) std::cout << "-1" << '\n';
	else std::cout << dp[(1 << stk.size()) - 1] << '\n';
}
posted @ 2021-07-23 13:56  Z_char  阅读(90)  评论(0编辑  收藏  举报