CF683div.2

C Knapsack

  贪心,如果一件物品的重量 \(C\) 满足 \(\lceil \frac{W}{2}\rceil\le C\le W\),则只选这一件,排除重量比 \(W\) 大的物品,不断加重量小于等于 \(\lceil \frac{W}{2}\rceil\) 的物品,直到总重量大于等于 \(\lceil \frac{W}{2}\rceil\),如果不行则无解。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;

#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f;

int t, n;
ll w;

int main() 
{
	scanf("%d", &t);
	while (t--) {
		scanf("%d%lld", &n, &w);
		vector<int> v;
		ll x, sum = 0;
		for (int i = 1; i <= n; ++i) {
			scanf("%lld", &x);
			if (x > w || sum >= (w + 1) / 2) continue;
			else if (x >= (w + 1) / 2) { v = {i}; sum = x; }
			else { sum += x; v.push_back(i); }
		}
		if (sum >= (w + 1) / 2) {
			printf("%d\n", (int)v.size());
			for (auto i : v) printf("%d ", i);
			puts("");
		}
		else puts("-1");
	}
    return 0;
}

D Catching Cheaters

  类似 LCS 的思想,\(dp[i][j]\) 表示第一个子串以 \(A_i\) 结尾第二个子串以 \(B_j\) 结尾的最大相似分数,则 \(dp[i][j]\) 至少为 0,每种情况下 \(dp[i][j]\) 都可以通过 \(dp[i-1][j]\)\(dp[i][j-1]\) 延长一个转移过来,\(A_i=B_j\)\(dp[i][j]=\max(dp[i][j], dp[i-1][j-1]+2)\),状态转移方程为:

\[dp[i][j]=\begin{cases}\max(dp[i][j],dp[i-1][j-1]+2)\quad A[i]==B[j]\\\max(dp[i-1][j],dp[i][j-1])-1\quad for\ each\ case\end{cases} \]

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
 
#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f, N = 5005;
 
int n, m, ans;
string A, B;
int dp[N][N];
 
int main() 
{
	scanf("%d%d", &n, &m);
	cin >> A >> B;
	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < m; ++j) {
			dp[i+1][j+1] = max(dp[i+1][j], dp[i][j+1]) - 1;
			if (A[i] == B[j]) {
				dp[i+1][j+1] = max(dp[i+1][j+1], max(dp[i][j], 0) + 2);
			}
			ans = max(ans, dp[i+1][j+1]);
		}
	}
	printf("%d\n", ans);
    return 0;
}

E Xor Tree

  建一颗 trie 树,高位靠近树根,如果一个节点左子树和右子树都包含超过 1 个节点,会形成两棵树,贪心把含数少的子树删成只有一个节点,最后保留的节点尽可能地多。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;

#define debug(x) cout << #x << " is " << x << endl
#define inc(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
const int INF = 0x3f3f3f3f, N = 2e5 + 5;

int n;
int tr[N*31][2], tot = 1;

void insert(int val) {
	int p = 1;
	for (int i = 30; i >= 0; --i) {
		int ch = val >> i & 1;
		if (!tr[p][ch]) tr[p][ch] = ++tot;
		p = tr[p][ch];
	}
}

int dfs(int p) {
	if (!p) return 0;
	if (!tr[p][0] && !tr[p][1]) return 1;
	return max(dfs(tr[p][0]) + (tr[p][1] > 0), dfs(tr[p][1]) + (tr[p][0] > 0));
}

int main() 
{
	scanf("%d", &n);
	int x;
	for (int i = 1; i <= n; ++i) {
		scanf("%d", &x);
		insert(x);
	}
	printf("%d\n", n - dfs(1));
    return 0;
}
posted @ 2020-11-17 22:25  2inf  阅读(95)  评论(0)    收藏  举报