A - Power
快速幂板子
点击查看代码
#include<cstdio>
#include<algorithm>
using namespace std;
#define int long long
int n, m;
int qpow(int a, int b) {
int res = 1;
while(b) {
if(b & 1) res *= a;
a *= a, b >>= 1;
}
return res;
}
signed main() {
scanf("%lld %lld", &n, &m);
printf("%lld", qpow(n, m));
return 0;
}
B - First Query Problem
跟着模拟就好,该修改就修改,该输出就输出。
点击查看代码
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 1e5 + 5;
//#define int long long
int n, m, a[N];
int qpow(int a, int b) {
int res = 1;
while(b) {
if(b & 1) res *= a;
a *= a, b >>= 1;
}
return res;
}
signed main() {
scanf("%d", &n);
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
scanf("%d", &m);
int op, x, y;
while(m --) {
scanf("%d", &op);
if(op == 1) {
scanf("%d %d", &x, &y);
a[x] = y;
}
else scanf("%d", &x), printf("%d\n", a[x]);
}
return 0;
}
C - Cash Register
倒着处理,如果数字为 1
~ 9
,加 1,
判断是否有 00
,如果有,只加 1。
点击查看代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1e5 + 5;
//#define int long long
int n, ans, a[N];
int qpow(int a, int b) {
int res = 1;
while(b) {
if(b & 1) res *= a;
a *= a, b >>= 1;
}
return res;
}
char s[N];
signed main() {
scanf("%s", s + 1);
n = strlen(s + 1);
for(int i = n; i; i --) {
if(i > 1 && s[i] == s[i - 1] && s[i] == '0') i --;
ans ++;
}
printf("%d", ans);
return 0;
}
D - Scope
因为题目保证输入字符串为合法,所以预处理出每个左右括号匹配的区间,st[i] ~ ed[i] (表示 s[i] 为 '(' 时的匹配区间)
因为是从左到右处理过来的,所以在 i 之前的括号区间肯定都处理过,因此可以直接跳过,
再拿个 bool 数组记录一下字母是否出现,完了。
点击查看代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 3e5 + 5;
//#define int long long
int n, ans, a[N], st[N], ed[N], top, sta[N];
char s[N];
bool vis[N], tag[N];
signed main() {
scanf("%s", s + 1);
n = strlen(s + 1);
for(int i = 1; i <= n; i ++) {
if(s[i] == '(' ) sta[++top] = i;
if(s[i] == ')') {
ed[sta[top]] = i;
st[i] = sta[top];
top --;
}
}
for(int i = 1; i <= n; i ++) {
if(s[i] != '(' && s[i] != ')') {
if(vis[s[i] - 'a']) {
puts("No");
return 0;
}
vis[s[i] - 'a'] = 1;
}
else if(s[i] == ')'){
for(int j = st[i] + 1; j <= i; j ++) {
while(ed[j] && j <= i) j = ed[j] + 1;
if(j > i) break;
if(s[j] != '(' && s[j] != ')') vis[s[j] - 'a'] = 0;
}
}
}
puts("Yes");
return 0;
}
E - Don't Isolate Elements
操作每次处理的是一行,因为每行有两种状态,A[i][j] or 1 - A[i][j]
分析可知,每行的可行性只与上下相邻的两行有关,
因此,定义状态 dp[i][j(0/1)][k(0/1)] 为 第 i - 1 行为 j 状态, 第 i 行为 k 状态时满足题意的最小操作数。
不难得出,dp[i][j][k] = min(dp[i - 1][h][j] + k) (h 为枚举的 i - 2 行的状态)
但需要判断三行状态为 h,j,k 时的合法性,
所以还要再写一个 check() 函数,特别注意 第 1 行 和 第 n 行的特殊性,需要单独判断、
点击查看代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1005;
//#define int long long
int n, m, ans = 1e9, s[N][N];
int dp[N][2][2];
bool check(int d, int now, int low, int up) {
int tmp;
if(d == 1) {
for(int i = 1; i <= m; i ++) {
tmp = 0;
if((s[d][i] ^ now) == (s[d + 1][i] ^ low)) tmp ++;
if(i > 1 && s[d][i] == s[d][i - 1]) tmp ++;
if(i < m && s[d][i] == s[d][i + 1]) tmp ++;
if(!tmp) return 0;
}
return 1;
}
for(int i = 1; i <= m; i ++) {
tmp = 0;
if((s[d][i] ^ now) == (s[d + 1][i] ^ low) || (s[d][i] ^ now) == (s[d - 1][i] ^ up)) tmp ++;
if(i > 1 && s[d][i] == s[d][i - 1]) tmp ++;
if(i < m && s[d][i] == s[d][i + 1]) tmp ++;
if(!tmp) return 0;
}
if(d == n - 1) {
for(int i = 1; i <= m; i ++) {
tmp = 0;
if((s[n][i] ^ low) == (s[d][i] ^ now)) tmp ++;
if(i > 1 && s[n][i] == s[n][i - 1]) tmp ++;
if(i < m && s[n][i] == s[n][i + 1]) tmp ++;
if(!tmp) return 0;
}
}
return 1;
}
signed main() {
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= m; j ++)
scanf("%d", &s[i][j]);
}
memset(dp, 0x3f, sizeof(dp));
dp[1][0][0] = dp[1][1][0] = 0, dp[1][1][1] = dp[1][0][1] = 1;
for(int i = 2; i <= n; i ++) {
for(int a = 0; a < 2; a ++) {
for(int b = 0; b < 2; b ++) {
for(int c = 0; c < 2; c ++) {
if(!check(i - 1, a, b, c)) continue;
dp[i][a][b] = min(dp[i][a][b], dp[i - 1][c][a] + b);
}
}
}
}
for(int i = 0; i < 2; i ++) {
for(int j = 0; j < 2; j ++) {
ans = min(dp[n][i][j], ans);
}
}
if(ans == 1e9) puts("-1");
else printf("%d",ans);
return 0;
}
F - Permutation Distance
考虑把绝对值去掉,并且将 \(P_i\) 和 \(i\) , \(P_j\) 和 \(j\) 分别放到一边。
那么就需要分类讨论:
- \(P_i + i + min(-P_j - j) (P_i > P_j, i > j)\)
- \(P_i - i + min(-P_j + j) (P_i > P_j, i < j)\)
- \(-P_i + i + min(P_j - j) (P_i < P_j, i > j)\)
- \(-P_i - i + min(P_j + h) (P_i < P_j, i < j)\)
于是问题就转化为求两个不等关系条件下的最小值(二维偏序),
我们就可以循环 \(i \in [1, n]\) 来控制一个不等条件,另一个条件用数据结构维护(线段树——单点修改,区间查询)。
即可求出最值。
点击查看代码
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 2e5 + 5, inf = 1e9;
struct node {
int l, r, a, b;
node(){}
node(int L, int R, int A, int B) {
l = L, r = R, a = A, b = B;
}
}tr[N << 4];
int n, A[N];
#define ls k << 1
#define rs k << 1 | 1
void pushup(int k) {
tr[k].a = min(tr[ls].a, tr[rs].a);
tr[k].b = min(tr[ls].b, tr[rs].b);
}
node merge(node x, node y) {
node res = node(x.l, y.r, min(x.a, y.a), min(y.b, x.b));
return res;
}
node query(int k, int st, int ed) {
if(tr[k].l >= st && tr[k].r <= ed) return tr[k];
int mid = (tr[k].l + tr[k].r) >> 1;
node res;
if(ed <= mid) return query(ls, st, ed);
else if(st > mid) return query(rs, st, ed);
else return merge(query(ls, st, ed), query(rs, st, ed));
}
void change(int k, int pos, int a, int b) {
if(tr[k].l == tr[k].r) {
tr[k].a = a, tr[k].b = b;
return;
}
int mid = (tr[k].l + tr[k].r) >> 1;
if(pos <= mid) change(ls, pos, a, b);
else change(rs, pos, a, b);
pushup(k);
}
void build(int k, int l, int r) {
if(l == r) {
tr[k] = node(l, r, inf, inf);
return;
}
tr[k].l = l, tr[k].r = r;
int mid = (l + r) >> 1;
build(ls, l, mid), build(rs, mid + 1, r);
pushup(k);
}
int ans[N];
int main() {
scanf("%d", &n);
memset(ans, 0x3f, sizeof(ans));
for(int i = 1; i <= n; i ++) {
scanf("%d", &A[i]);
}
build(1, 1, n);
// puts("*2");
for(int i = 1; i <= n; i ++) {
if(A[i] > 1) ans[i] = min(ans[i], A[i] + i + query(1, 1, A[i] - 1).a);
if(A[i] < n) ans[i] = min(ans[i], i - A[i] + query(1, A[i] + 1, n).b);
change(1, A[i], - A[i] - i, A[i] - i);
}
build(1, 1, n);
for(int i = n; i; i --) {
if(A[i] > 1) ans[i] = min(ans[i], A[i] - i + query(1, 1, A[i] - 1).a);
if(A[i] < n) ans[i] = min(ans[i], - i - A[i] + query(1, A[i] + 1, n).b);
change(1, A[i], - A[i] + i, A[i] + i);
}
for(int i = 1; i <= n; i ++) printf("%d ", ans[i]);
return 0;
}