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\) 是否可行。显然有:
但暴力转移复杂度 \(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}\)

浙公网安备 33010602011771号