T1
T组输入,每组输入地图的大小 n ∗ m n*m n∗m,并且地图上每一个点都存在一个犯人,每个犯人可以花费一个晚上走到相邻的四个格子,现在(x,y)处有一个逃生通道,询问最后一个走的犯人需要花费几个夜晚到达。
判断地图的四个端点寻找距离最大者即可。
#include <bits/stdc++.h>
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define all(__vv__) (__vv__).begin(), (__vv__).end()
#define endl "\n"
#define pai pair<int, int>
#define ms(__x__,__val__) memset(__x__, __val__, sizeof(__x__))
typedef long long ll; typedef unsigned long long ull; typedef long double ld;
inline ll read() { ll s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar()) s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; }
inline void print(ll x, int op = 10) { if (!x) { putchar('0'); if (op) putchar(op); return; } char F[40]; ll tmp = x > 0 ? x : -x; if (x < 0)putchar('-'); int cnt = 0; while (tmp > 0) { F[cnt++] = tmp % 10 + '0'; tmp /= 10; } while (cnt > 0)putchar(F[--cnt]); if (op) putchar(op); }
inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
ll qpow(ll a, ll b) { ll ans = 1; while (b) { if (b & 1) ans *= a; b >>= 1; a *= a; } return ans; } ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; }
const int dir[][2] = { {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int N = 1e6 + 7;
int n, m;
int cnt[10];
void solve() {
int n = read(), m = read(), a = read(), b = read();
cnt[1] = a - 1 + b - 1;
cnt[2] = n - a + b - 1;
cnt[3] = a - 1 + m - b;
cnt[4] = n - a + m - b;
int ans = 0;
for (int i = 1; i <= 4; ++i)
ans = max(ans, cnt[i]);
print(ans);
}
int main() {
int T = read(); while (T--)
solve();
return 0;
}
T2
给出一个长度为n的颜色数组,对应每个颜色值是
a
i
a_i
ai,每次你可以操作长度为m的连续子数组,把他们的颜色改成一个相同的值。询问你把全部的数改成同一个颜色的最小操作次数是几次。
n
,
m
≤
1
0
5
,
a
i
≤
100
n,m\leq10^5,a_i\leq100
n,m≤105,ai≤100
数据范围比较友好,暴力遍历全部出现的颜色,再判断一下如果使用这个颜色需要修改几次。
const int N = 1e6 + 7;
int n, m;
int a[N], b[N];
void solve() {
int maxi = 0, mini = INF;
n = read(), m = read();
unordered_set<int> st;
for (int i = 1; i <= n; ++i) {
a[i] = read();
st.insert(a[i]);
}
int ans = INF;
for(auto& i : st){
int cnt = 0;
for (int j = 1; j <= n; ++j) {
if (a[j] == i) continue;
else {
++cnt;
j += m-1;
}
}
ans = min(ans, cnt);
}
print(ans);
}
T3
跳板模型,给你长度为n的01串,0代表这个位置没有跳板,1代表这个位置有跳板。你一开始会把球扔在下标为p(从1开始计算下标),并且下次球会弹跳到p+k处,在下次就会到p+2*k处,直到弹出n外面。现在如果一个落点没有跳板,那么你的球就死了,现在你可以在任意位置添加一块跳板花费的金钱是x,你也可以移除最开头的跳板花费是y,并且移除操作只可以对开头连续的串进行。询问你要成功活着跳到n外面去的最小花费是多少。
1
≤
p
≤
n
≤
1
0
5
,
1
≤
k
≤
n
,
1
≤
x
,
y
≤
1
0
4
1\leq p\leq n\leq10^5 , 1\leq k\leq n, 1\leq x,y\leq 10^4
1≤p≤n≤105,1≤k≤n,1≤x,y≤104
首先如果我们不看可以移除开头格子的话,使用倒序的一个dp递推,可以求到每个位置后面最少要添加几块跳板。接下来我们就再去枚举我们移除开头几个格子就行了,移除i个格子的话,说明我们的起始落点就变成p+i了,但是注意的是,题目没说可以移除n-p+1个格子。也就是直接丢出去,不经历一次跳板是不合法的,因为这个一直wa。
const int N = 1e6 + 7;
char s[N];
ll dp[N];
void solve() {
ll n = read(), p = read(), k = read();
scanf("%s", s + 1);
ms(dp, 0); // 求以i为落点,后面还需要添加几个跳板
for (ll i = 1; i <= k; ++i) {
dp[n - i + 1] = (s[n - i + 1] == '0');
}
for (ll i = n - k; i; --i) {
dp[i] = (s[i] == '0') + dp[i + k];
}
ll x = read(), y = read();
ll ans = 1e18;
for (ll i = 0; i <= n - p; ++i) { // 枚举去掉的开头跳板
ll tmp = y * i;
if (i + p <= n) tmp += x * dp[i + p];
ans = min(ans, tmp);
}
print(ans);
}
T4
起始给出长度为n的非递减序列,你每次可以选择两个相邻的元素进行异或操作,并且把两数异或的结果放入之前位置,但是拿走两个数只放回一个数。询问你如果要把序列变得不是非递减的最少要进行几次异或操作,如果永远都无法变得不是非递减输出-1。
2
≤
n
≤
1
0
5
,
1
≤
a
i
≤
1
0
9
2\leq n\leq10^5,1\leq a_i\leq10^9
2≤n≤105,1≤ai≤109
首先我们看异或题,都尽可能转换成二进制考虑一下,如果我们使用 b i b_i bi记录每个位置的二进制最高次,如果出现了三个连续的数他们的二进制最高次幂是相同的,也就是 b i − 1 = b i = b i + 1 b_{i-1}=b_i=b_{i+1} bi−1=bi=bi+1这样的三个点,我们可以选择 a i ⊕ a i + 1 a_i\oplus a_{i+1} ai⊕ai+1这样处理完之后他们的之前最高次一定是0了,一定会保证 a i − 1 > a i ⊕ a i + 1 a_{i-1}>a_i\oplus a_{i+1} ai−1>ai⊕ai+1。我们可以发现大概有31位二进制位,如果大于了62位左右的话一定会有3个的相同二进制位,这样我们直接输出1就可以了。那么接下来的对于 n ≤ 70 n\leq70 n≤70的,直接暴力枚举全部可能的区间,可以使用异或前缀和加速一下。
const int N = 1e5 + 7;
ll n, m;
int pre[N]; // 前缀异或和
void solve() {
n = read();
rep(i, 1, n) pre[i] = pre[i - 1] ^ read();
if (n == 2) { puts("-1"); return; }
if (n >= 70) { print(1); return; }
int ans = INF;
rep(i, 1, n - 1) {
rep(j, i + 1, n) {
rep(k, i, j - 1) {
int tmp1 = pre[k] ^ pre[i - 1];
int tmp2 = pre[j] ^ pre[k];
if (tmp1 > tmp2) ans = min(ans, j - i - 1); // 合并成2个数
int tmp3 = tmp1 ^ tmp2;
if (i != 1 and tmp3 < (pre[i - 1] ^ pre[i - 2]))
ans = min(ans, j - i); // 多花一次合并分隔的两数
if (j != n and tmp3 > (pre[j + 1] ^ pre[j]))
ans = min(ans, j - i);
}
}
}
if (ans == INF) print(-1);
else print(ans);
}