2022杭电多校 补题

1

赛中通过:\(\texttt{BKL}\)

C. Backpack

题意

\(T(1\le T\le10)\) 组数据, \(n\) 个物品,容量为 \(m\) 的背包 \((1\le n,m<2^{10})\) 。每个物品有价值 \(v_i\) , 重量 \(w_i(1\le v_i,w_i<2^{10})\) 。求正好装满背包的情况下,最大的物品价值的异或和

思路

考虑 \(dp\) ,设 \(f_{i,j,k}\) 为前 \(i\) 个物品,异或和为 \(j\) ,重量为 \(k\) 是否可行。显然有:

\[f_{i,j,k}=f_{i-1,j,k}\or f_{i-1,j\oplus v_i,k_i-w_i} \]

但暴力转移复杂度 \(O(T\cdot n^3)\) 显然无法通过,发现可以使用 \(bitset\) 优化, \(f_{i,j}\) 的各状态用一个 \(bitset\) 来维护,于是转移变为 \(f_{i,j}=f_{i-1,j}\or (f_{i-1,j\oplus v_i}<<w_i)\) ,复杂度变为 \(O(T\cdot\frac{n^3}{\omega})\) ,可以通过。

代码

#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
using namespace std;
using LL = long long;
using LD = long double;
using ULL = unsigned long long;
using PII = pair<int, int>;
using TP = tuple<int, int, int>;
#define all(x) x.begin(),x.end()
#define mst(x,v) memset(x,v,sizeof(x))
#define mk make_pair
//#define int LL
#define double LD
//#define lc p*2
//#define rc p*2+1
#define endl '\n'
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#pragma warning(disable : 4996)
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const double eps = 1e-8;
const double pi = acos(-1);
const LL MOD = 1000000007;
const LL mod = 998244353;
const int maxn = 1030;

int T, N, M, w[maxn], v[maxn];
bitset<maxn>f[2][maxn];

void solve()
{
	f[0][0] = 1;
	for (int i = 1; i <= N; i++)
	{
		for (int j = 0; j < 1024; j++)
			f[i % 2][j] = f[(i % 2) ^ 1][j] | (f[(i % 2) ^ 1][j ^ v[i]] << w[i]);
		for (int j = 0; j < 1024; j++)
			f[(i % 2) ^ 1][j] = f[i % 2][j];
	}
	int ans = -1;
	for (int i = 0; i < 1024; i++)
	{
		if (f[N % 2][i][M])
			ans = i;
	}
	cout << ans << endl;
}

int main()
{
	IOS;
	cin >> T;
	while (T--)
	{
		cin >> N >> M;
		for (int i = 0; i < 1024; i++)
			f[0][i].reset(), f[1][i].reset();
		for (int i = 1; i <= N; i++)
			cin >> w[i] >> v[i];
		solve();
	}
	return 0;
}

D. Ball

题意

\(T(1\le T\le10)\) 组数据, \(m\cdot m(1\le m\le10^5)\) 的棋盘 , \(n(1\le n\le2000)\) 个点 \(p_i:(x_i,y_i)(1\le x_i,y_i\le m)\) 。求三元组 \((i,j,k)\) 的个数,满足 \(p_i,p_j,p_k\) 三者两两间曼哈顿距离的中位数为素数。

思路

首先我们最大的曼哈顿距离为 \(2m\) ,我们可以先筛出 \(2m\) 内所有素数,之后考虑将每组点对看作边,枚举所有长度为素数的边,求有多少条边的长度分别 \(\le\)\(\ge\) 该边长度,暴力枚举复杂度 \(O(n^3)\) ,难以接受,考虑优化。如果我们建立一个邻接矩阵 \(G\)\(G[i][j]\) 表示从点 \(i\) 到点 \(j\) 的边。对于当前枚举的边 \((a,b)\) ,如果 \(dis(i,j)\le dis(a,b)\)\(G[i][j]\)\(0\) ,否则为 \(1\) 。于是边 \((a,b)\) 对答案的贡献就为 \(G[a]\oplus G[b]\)\(1\) 的个数,我们将所有边按长度从小到大排序来方便枚举,一开始整个 \(G\) 皆为 \(0\) ,之后每计算完一条边 \((a,b)\) ,就令 \(G[a][b],G[b][a]\)\(1\) 即可完成 \(G\) 的更新。在枚举到连续若干条长度相等的边时,这样枚举可以理解为在按下标枚举来区分这些边,从而保证不重不漏。边数 \(O(n^2)\) ,计算的复杂度为 \(O(\frac{n}{\omega})\) 。于是总的复杂度为 \(O(T\cdot\frac{n^3}{\omega})\) ,可以通过。

代码

#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
using namespace std;
using LL = long long;
using LD = long double;
using ULL = unsigned long long;
using PII = pair<int, int>;
using TP = tuple<int, int, int>;
#define all(x) x.begin(),x.end()
#define mst(x,v) memset(x,v,sizeof(x))
#define mk make_pair
//#define int LL
//#define double LD
//#define lc p*2
//#define rc p*2+1
#define endl '\n'
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#pragma warning(disable : 4996)
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const double eps = 1e-8;
const double pi = acos(-1);
const LL MOD = 1000000007;
const LL mod = 998244353;
const int maxm = 200010;
const int maxn = 2010;

struct line {
	int a, b, c;
	bool operator<(const line& rhs)const
	{
		return c < rhs.c;
	}
};
bool is_prime[maxm];
int N, M, T, v[maxm], prime[maxm];
PII p[maxn];
vector<line>l;
bitset<maxn>G[maxn];

int dis(int x1, int y1, int x2, int y2)
{
	return abs(x2 - x1) + abs(y2 - y1);
}

int primes(int n)
{
	mst(v, 0);
	int m = 0;
	for (int i = 2; i <= n; i++)
	{
		if (!v[i])
		{
			v[i] = i;
			prime[++m] = i, is_prime[i] = true;
		}
		for (int j = 1; j <= m; j++)
		{
			if (prime[j] > v[i] || prime[j] > n / i)
				break;
			v[prime[j] * i] = prime[j];
		}
	}

	return m;
}

void solve()
{
	LL ans = 0;
	l.clear();
	for (int i = 0; i < N; i++)
	{
		G[i].reset();
		for (int j = i + 1; j < N; j++)
		{
			int d = dis(p[i].first, p[i].second, p[j].first, p[j].second);
			l.push_back(line{ i,j,d });
		}
	}
	sort(all(l));
	for (auto& k : l)
	{
		if (is_prime[k.c])
			ans += (G[k.a] ^ G[k.b]).count();
		G[k.a][k.b] = G[k.b][k.a] = 1;
	}
	cout << ans << endl;
}

int main()
{
	IOS;
	int ps = primes(200000);
	cin >> T;
	while (T--)
	{
		cin >> N >> M;
		for (int i = 0; i < N; i++)
			cin >> p[i].first >> p[i].second;
		solve();
	}

	return 0;
}

I. Laser

代码

#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
using namespace std;
using LL = long long;
using LD = long double;
using ULL = unsigned long long;
using PII = pair<LL, LL>;
using TP = tuple<int, int, int>;
#define all(x) x.begin(),x.end()
#define mst(x,v) memset(x,v,sizeof(x))
#define mul(x,y) (1ll*(x)*(y)%mod)
#define mk make_pair
#define int LL
//#define double LD
//#define lc p*2
//#define rc p*2+1
#define endl '\n'
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#pragma warning(disable : 4996)
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const double eps = 1e-8;
const double pi = acos(-1);
const LL MOD = 1000000007;
const LL mod = 1004535809;
const int maxn = 500010;

int T, N;
PII P[maxn], Q[maxn];

bool check(int x, int y)
{
	for (int i = 1; i <= N; i++)
	{
		int a = Q[i].first, b = Q[i].second;
		if (a + b == x + y)
			continue;
		if (b - a == y - x)
			continue;
		if (a == x)
			continue;
		if (b == y)
			continue;
		return false;
	}
	return true;
}

bool calc()
{
	bool flag = false;
	int sx = Q[1].first, sy = Q[1].second;
	int tx = INF, ty = INF;
	for (int i = 2; i <= N; i++)
	{
		if (Q[i].first == sx)
			continue;
		tx = Q[i].first, ty = Q[i].second;
		break;
	}
	if (tx != INF && ty != INF)
		flag = check(sx, ty) || check(sx, ty - tx + sx) || check(sx, ty + tx - sx);
	else
		flag = true;
	return flag;
}

void solve()
{
	bool flag = false;
	if (N == 1)
	{
		cout << "YES" << endl;
		return;
	}
	for (int i = 1; i <= N; i++)
		Q[i].first = P[i].first, Q[i].second = P[i].second;
	flag |= calc();
	for (int i = 1; i <= N; i++)
		Q[i].first = P[i].second, Q[i].second = P[i].first;
	flag |= calc();
	for (int i = 1; i <= N; i++)
		Q[i].first = P[i].first + P[i].second, Q[i].second = P[i].second - P[i].first;
	flag |= calc();
	for (int i = 1; i <= N; i++)
		Q[i].first = P[i].second - P[i].first, Q[i].second = P[i].first + P[i].second;
	flag |= calc();
	cout << (flag ? "YES" : "NO") << endl;
}

signed main()
{
	IOS;
	cin >> T;
	while (T--)
	{
		cin >> N;
		for (int i = 1; i <= N; i++)
			cin >> P[i].first >> P[i].second;
		solve();
	}

	return 0;
}

2

赛中通过:\(\texttt{ABCGIL}\)

posted @ 2022-07-21 20:46  Prgl  阅读(62)  评论(0)    收藏  举报