2022杭电多校补题1
1002
思路
由于数据量较小,可以考虑二进制枚举+bfs
刚开始是可以任意走的
我们可以做一个放大的操作(*2倍),这样可以避免double的影响
不仅如此,放大以后只能向上下左右四个方向走,可以证明斜着走的情况并不存在(因为墙壁坐标放大以后都是偶数)
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int maxn = 1 << 16;
const int nx[4] = {0, 1, 0, -1};
const int ny[4] = {1, 0, -1, 0};
struct Node
{
int x, y;
int sta, cnt = 0;
bool operator<(const Node &node) const
{
return cnt > node.cnt;
}
};
int n, m, k;
int sx, sy, tx, ty;
bool vis[16][16][maxn];
int matrix[35][35];
int bfs()
{
memset(vis, 0, sizeof(vis));
priority_queue<Node> q;
Node it;
it.x = 2 * sx + 1;
it.y = 2 * sy + 1;
it.sta = 0;
it.cnt = 0;
q.push(it);
while (!q.empty())
{
Node fr = q.top();
q.pop();
if (vis[(fr.x - 1) / 2][(fr.y - 1) / 2][fr.sta])
continue;
vis[(fr.x - 1) / 2][(fr.y - 1) / 2][fr.sta] = 1;
if (fr.x == 2 * tx + 1 && fr.y == 2 * ty + 1)
return fr.cnt;
for (int i = 0; i < 4; ++i)
{
Node it = fr;
int xx = fr.x + nx[i], yy = fr.y + ny[i];
if (xx <= 0 || xx >= 2 * n || yy <= 0 || yy >= 2 * m)
continue;
if (matrix[xx][yy] && ((fr.sta >> matrix[xx][yy]) & 1) == 0)
{
it.sta |= (1 << matrix[xx][yy]);
++it.cnt;
}
it.x += 2 * nx[i];
it.y += 2 * ny[i];
q.push(it);
}
}
return -1;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int t;
cin >> t;
while (t--)
{
memset(matrix, 0, sizeof(matrix));
cin >> n >> m >> k;
cin >> sx >> sy >> tx >> ty;
int x1, y1, x2, y2;
for (int i = 1; i <= k; ++i)
{
cin >> x1 >> y1 >> x2 >> y2;
if (x1 == x2)
{
for (int j = 2 * min(y1, y2); j <= 2 * max(y1, y2); ++j)
matrix[2 * x1][j] = i;
}
if (y1 == y2)
{
for (int j = 2 * min(x1, x2); j <= 2 * max(x1, x2); ++j)
matrix[j][2 * y1] = i;
}
}
cout << bfs() << '\n';
}
return 0;
}
1003
思路
求当背包放满的时候,最大的异或和。
这道题直接暴力的话复杂度是O(n^3),可能会超时,所以考虑bitset优化
f[i][j] 表示异或值为i时,是否可以组合成背包容量为j的方案
如果为1就是可以组合
为0就是无法组合
转移方程就是 f[j] |= g[j ^ w];
在转移之前要记得先把当前体积考虑进去————g[j] = f[j] << v;
因为 j ^ w ^ w = j;
所以转移之后就是当异或值为j时并且考虑了这个物品之后的体积方案
最后从大到小遍历一遍,找到最大的满足m的i值(异或值)
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1100;
bitset<N> f[N], g[N];
int n, m;
signed main()
{
int T;
cin >> T;
while (T--)
{
cin >> n >> m;
for (int i = 0; i <= 1024; i++)
f[i].reset(), g[i].reset();
f[0][0] = 1;
for (int i = 1; i <= n; i++)
{
int w, v;
cin >> v >> w;
for (int j = 0; j < 1024; j++)
{
g[j] = f[j] << v;
}
for (int j = 0; j < 1024; j++)
{
f[j] |= g[j ^ w];
}
}
bool flag = false;
for (int i = 1024; i >= 0; i--)
if (f[i][m])
{
flag = true;
cout << i << endl;
break;
}
if (!flag)
cout << "-1" << endl;
}
return 0;
}
1009
思路
暴力枚举
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N = 1e5 + 10;
int n, a[N], b[N], x[N], y[N];
bool ptsd(int x, int y)
{
if (!x || !y || x + y == 0 || x == y)
return true;
return false;
}
bool ck(int xx, int yy)
{
for (int i = 1; i <= n; i++)
if (!ptsd(xx - x[i], yy - y[i]))
return false;
return true;
}
bool check()
{
bool flag = true;
for (int i = 1; i <= n; i++)
{
if (x[i] == x[1])
continue;
flag = false;
if (ck(x[1], y[i]))
return true;
if (ck(x[1], y[i] + (x[i] - x[1])))
return true;
if (ck(x[1], y[i] - (x[i] - x[1])))
return true;
}
if (!flag)
return false;
return true;
}
signed main()
{
int T;
cin >> T;
while (T--)
{
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i] >> b[i];
for (int i = 1; i <= n; i++)
x[i] = a[i], y[i] = b[i];
if (check())
{
cout << "YES" << endl;
continue;
}
for (int i = 1; i <= n; i++)
x[i] = b[i], y[i] = a[i];
if (check())
{
cout << "YES" << endl;
continue;
}
for (int i = 1; i <= n; i++)
x[i] = a[i] + b[i], y[i] = a[i] - b[i];
if (check())
{
cout << "YES" << endl;
continue;
}
for (int i = 1; i <= n; i++)
x[i] = a[i] - b[i], y[i] = a[i] + b[i];
// cout << 1 << endl;
if (check())
cout << "YES" << endl;
else
cout << "NO" << endl;
}
return 0;
}
1012
思路
博弈的题一般都具有一定的规律,通过举例我们可以发现两个1 alice一定能赢
4个2 alice一定能赢,因为4个2可以转化为2个1
同样的道理,8个3 alice一定能赢,8个3可以转化为4个2
对alice来说,每一次都应该将数尽可能地平分
对bob来说,每一次他都应该把出现次数多地一堆删掉
由此我们可以知道,每个数的一半可以向下转化,最后检查0的个数即可
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N = 1e6 + 5;
int s[N];
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while(t--){
int n;
cin >> n;
for(int i = 0; i <= n; i++){
cin >> s[i];
}
for(int i = n-1; i >= 0; i--){
s[i] += s[i+1]/2;
}
if(s[0]) cout << "Alice" << endl;
else cout << "Bob" << endl;
}
return 0;
}