(ACM) 期末考试
(A. Alphabet)
题意
给定一个由小写字母组成的字符串 (s),可以在任意位置插入任意数量的小写字母
计算最少插入多少小写字母,使得新字符串 (s') 中含有子序列 abcdefghijklmnopqrstuvwxyz
(|s| < 50)
题解
即求字符串中的最长上升子序列
定义 (dp[i]) 为到 (i) 位置所具备的最长上升子序列,则 (dp[i] = maxleft{dp[j] + 1, j < i ight})
(O(n^2)) 暴力转移
(code)
#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int, int>
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], "
"[i == r])
typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL MOD = 11092019;
const int inf = 0x3f3f3f3f;
const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
const int N = 1e5 + 7;
const double PI = acos(-1);
const double EPS = 1e-6;
using namespace std;
inline int read()
{
char c = getchar();
int ans = 0, f = 1;
while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
return ans * f;
}
char str[107];
int dp[107];
int main()
{
scanf("%s", str + 1);
int L = strlen(str + 1);
for(int i = 1; i <= L; ++i){
dp[i] = 1;
for(int j = 1; j < i; ++j)
if(str[j] < str[i]) dp[i] = max(dp[i], dp[j] + 1);
}
int ans = 0;
//for(int i = 1; i <= L; ++i) cout << i << ' ' << dp[i] <<endl;
for(int i = 1; i <= L; ++i) ans = max(ans, dp[i]);
printf("%d
", 26 - ans);
return 0;
}
(B. Barbells)
题意
有 (n) 个杠铃和 (m) 个杠铃片,(n, mleq 14)
在满足杠铃两端重量一致的前提下,计算这些器件一共可以组和出多少种不同的重量
题解
双重二进制枚举杠铃片的选则,(check) 重量是否一致,用与运算判断是否为独立集合即可
(code)
#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int, int>
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], "
"[i == r])
typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL MOD = 11092019;
const int inf = 0x3f3f3f3f;
const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
const int N = 1e5 + 7;
const double PI = acos(-1);
const double EPS = 1e-6;
using namespace std;
inline int read()
{
char c = getchar();
int ans = 0, f = 1;
while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
return ans * f;
}
int n, m;
LL a[20], b[20];
set<LL> st;
int main()
{
n = read(), m = read();
for(int i = 0; i < n; ++i) scanf("%lld", &a[i]);
for(int i = 0; i < m; ++i) scanf("%lld", &b[i]);
for(int i = 0; i < (1 << m); ++i) {
for(int j = 0; j < (1 << m); ++j) {
if((i & j) == 0) {
LL x = 0, y = 0;
for(int k = 0; k < m; ++k) {
if(i & (1 << k)) x += b[k];
if(j & (1 << k)) y += b[k];
}
if(x == y) st.insert(x + y);
}
}
}
set<LL> ans;
for(auto i: st) {
for(int j = 0; j < n; ++j)
ans.insert(i + a[j]);
}
for(auto i: ans) cout << i << endl;
return 0;
}
(C, Buggy Robot)
题意
在一个 (n imes m) 的二维迷宫上,给一个机器人输入一串 URDL
的指令 (s, |s| leq 50),操纵其从入口走到出口
机器人按照指令移动
- 若当前指令使得机器人遇到障碍物
#
或者走出边界,那么机器人会忽视当前指令 - 若走到终点,剩下的所有指令作废
已知指令错误,现在允许在任意位置插入新指令,也允许删除任意指令,亦可以不改变指令
计算最小的修改次数,使得机器人可以走到终点
(n, m, |s|leq 50)
题解
定义 (dp[i][j][k]) 为执行第 (k) 条指令后,机器人走到 ((i, j)) 位置时所需要修改的最小次数
考虑状态转移
- 若删除当前指令,则 (dp[i][j][k + 1] = min(dp[i][j][k + 1], dp[i][j][k] + 1))
- 若在当前位置增添指令,则 (dp[i'][j'][k] = min(dp[i'][j'][k], dp[i][j][k] + 1))
- 若什么也不做,则 (dp[i'][j'][k + 1] = min(dp[i'][j'][k + 1], dp[i][j][k]))
用 (bfs) 暴力转移
(code)
#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int, int>
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], "
"[i == r])
typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL MOD = 11092019;
const int inf = 0x3f3f3f3f;
const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
const int N = (1 << 20) + 7;
const double PI = acos(-1);
const double EPS = 1e-6;
using namespace std;
inline int read()
{
char c = getchar();
int ans = 0, f = 1;
while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
return ans * f;
}
int n, m, mp[10];
char g[100][100], str[100];
int dp[100][100][100];
struct node
{
int x, y, pos;
node() {}
node(int _x, int _y, int _pos) {x = _x, y = _y, pos = _pos;}
};
bool check(int x, int y) {return x >= 1 && x <= n && y >= 1 && y <= m && g[x][y] != '#';}
void bfs(int sx, int sy, int ex, int ey, int L)
{
queue<node> q;
dp[sx][sy][0] = 0;
q.push(node(sx, sy, 0));
while(!q.empty()) {
node temp = q.front(); q.pop();
for(int i = 1; i <= 4; ++i) {
int tx = temp.x + DX[i], ty = temp.y + DY[i];
if(check(tx, ty) && dp[tx][ty][temp.pos] > dp[temp.x][temp.y][temp.pos] + 1) {
dp[tx][ty][temp.pos] = dp[temp.x][temp.y][temp.pos] + 1;
q.push(node(tx, ty, temp.pos));
}
}
if(temp.pos < L) {
if(dp[temp.x][temp.y][temp.pos + 1] > dp[temp.x][temp.y][temp.pos] + 1) {
dp[temp.x][temp.y][temp.pos + 1] = dp[temp.x][temp.y][temp.pos] + 1;
q.push(node(temp.x, temp.y, temp.pos + 1));
}
int tpos = temp.pos + 1;
int tx = temp.x + DX[mp[str[tpos]]], ty = temp.y + DY[mp[str[tpos]]];
if(!check(tx, ty)) tx = temp.x, ty = temp.y;
if(dp[tx][ty][tpos] > dp[temp.x][temp.y][temp.pos]) {
dp[tx][ty][tpos] = dp[temp.x][temp.y][temp.pos];
q.push(node(tx, ty, tpos));
}
}
}
}
int main()
{
int sx, sy, ex, ey;
mp['U'] = 1, mp['R'] = 2, mp['D'] = 3, mp['L'] = 4;
scanf("%d %d", &n, &m);
memset(dp, inf, sizeof(dp));
for(int i = 1; i <= n; ++i)
scanf("%s", g[i] + 1);
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= m; ++j) {
if(g[i][j] == 'R') sx = i, sy = j;
if(g[i][j] == 'E') ex = i, ey = j;
}
}
scanf("%s", str + 1);
int L = strlen(str + 1);
bfs(sx, sy, ex, ey, L);
int ans = inf;
for(int i = 1; i <= L; ++i) ans = min(ans, dp[ex][ey][i]);
printf("%d
", ans);
return 0;
}
后记
感觉这题相当难想,也相当难写,需要仔细体会
(D. Cameras)
题意
有 (n) 个房子,其中 (k) 个房子有灯
现在要求每 (r) 个连续房子至少得有两个房子有灯,计算需要增加的灯的个数
(nleq 100000, 0leq kleq n)
题解
贪心,优先往右边的房子放灯
嵌套循环寻找右边第一个没有灯的位置,该位置灯的数量加一,注意这个嵌套循环最多循环三次,复杂度最多带个常数 (3)
要求快速查询区间内灯的个数,以及单点修改,所以考虑用树状数组进行维护
(code)
#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int, int>
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], "
"[i == r])
typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL MOD = 11092019;
const int inf = 0x3f3f3f3f;
const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
const int N = 1e5 + 7;
const double PI = acos(-1);
const double EPS = 1e-6;
using namespace std;
inline int read()
{
char c = getchar();
int ans = 0, f = 1;
while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
return ans * f;
}
int n, k, r, a[N];
//BIT
int c[N];
int lowbit(int x) {return x & (-x);}
void upd(int *c, int i, int val)
{
while(i <= n){
c[i] += val;
i += lowbit(i);
}
}
int query(int *c, int i)
{
int ans = 0;
while(i > 0) {
ans += c[i];
i -= lowbit(i);
}
return ans;
}
int main()
{
n = read(), k = read(), r = read();
for(int i = 1; i <= k; ++i) {
int x = read();
a[x] = 1;
upd(c, x, 1);
}
int ans = 0;
for(int i = 1; i <= n - r + 1; ++i) {
int num = query(c, i + r - 1) - query(c, i - 1);
if(num < 2) {
int t = 0;
for(int j = i + r - 1; j >= i; --j) {
if(!a[j]) upd(c, j, 1), t++;
if(t == 2 - num) break;
}
ans += 2 - num;
}
}
cout << ans << endl;
return 0;
}
(E. Contest Score)
题意
设某次 (xcpc) 共有 (n) 个题目,现给定一个队伍对于每道题的解题时间 (t_{i}),以及竞赛策略
- (1.) 先读前 (k) 个题
- (2.) 选择花费时间最少的题目进行解答
- (3.) 如果还有题目剩余,读下一个题目
- (4.) 如果还有没做完的题目,回到 (2)
假设读题不花费时间,输出罚时
(1leq kleq nleq 300, 1leq t_{i}leq 1000000)
题解
签到,优先队列模拟即可
(code)
#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int, int>
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], "
"[i == r])
typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL MOD = 11092019;
const int inf = 0x3f3f3f3f;
const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
const int N = 1e5 + 7;
const double PI = acos(-1);
const double EPS = 1e-6;
using namespace std;
inline int read()
{
char c = getchar();
int ans = 0, f = 1;
while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
return ans * f;
}
int n, k;
LL t[500];
priority_queue<LL, vector<LL>, greater<LL> > pq;
int main()
{
ios::sync_with_stdio(false);
cin >> n >> k;
LL time = 0, ans = 0;
int cnt = k + 1;
for(int i = 1; i <= n; ++i) cin >> t[i];
for(int i = 1; i <= k; ++i) pq.push(t[i]);
while(!pq.empty()) {
time += pq.top(); ans += time; pq.pop();
if(cnt <= n) pq.push(t[cnt++]);
}
cout << ans << endl;
return 0;
}
(F. Equality)
题意
给定 (a + b = c),判断等式是否成立
题解
签到,格式化读入之后判断即可
(code)
#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int, int>
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], "
"[i == r])
typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL MOD = 11092019;
const int inf = 0x3f3f3f3f;
const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
const int N = 1e5 + 7;
const double PI = acos(-1);
const double EPS = 1e-6;
using namespace std;
inline int read()
{
char c = getchar();
int ans = 0, f = 1;
while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
return ans * f;
}
int main()
{
int a, b, c;
scanf("%d + %d = %d", &a, &b, &c);
puts(a + b == c ? "YES" : "NO");
return 0;
}
(G. Gravity)
题意
给定一个 (n imes m) 的二维格点图,模拟苹果受重力的掉落情况
(1leq n, mleq 50)
题解
签到,模拟即可
(code)
#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int, int>
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], "
"[i == r])
typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL MOD = 11092019;
const int inf = 0x3f3f3f3f;
const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
const int N = 1e5 + 7;
const double PI = acos(-1);
const double EPS = 1e-6;
using namespace std;
inline int read()
{
char c = getchar();
int ans = 0, f = 1;
while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
return ans * f;
}
int n, m;
char g[100][100];
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; ++i)
scanf("%s", g[i] + 1);
for(int j = 1; j <= m; ++j) {
for(int i = n; i >= 1; --i) {
if(g[i][j] == 'o') {
g[i][j] = '.';
int f = 0;
for(int k = i; k <= n; ++k)
if(g[k][j] == 'o' || g[k][j] == '#') {g[k - 1][j] = 'o'; f = 1; break;}
if(!f) g[n][j] = 'o';
}
}
}
for(int i = 1; i <= n; ++i)
printf("%s
", g[i] + 1);
return 0;
}
(H. Islands)
题意
给定一个 (n imes m) 的二维格点图,(L) 表示陆地,(W) 表示海洋,(C) 表示云朵,云朵既可以变成海洋也可以变成陆地
恰当地变换 (C) 的形态,计算图中最少有多少陆地连通块
(1leq n, mleq 50)
题解
把所有与 (L) 相连通的 (C) 全部变成 (L),因为这样连通块个数才不会增加
(dfs) 即可
(code)
#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int, int>
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], "
"[i == r])
typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL MOD = 11092019;
const int inf = 0x3f3f3f3f;
const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
const int N = 1e5 + 7;
const double PI = acos(-1);
const double EPS = 1e-6;
using namespace std;
inline int read()
{
char c = getchar();
int ans = 0, f = 1;
while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
return ans * f;
}
int n, m, vis[100][100];
char g[100][100];
bool check(int x, int y) {return x >= 1 && x <= n && y >= 1 && y <= m;}
void dfs(int x, int y)
{
vis[x][y] = 1;
for(int i = 1; i <= 4; ++i) {
int tx = x + DX[i], ty = y + DY[i];
if(!vis[tx][ty] && check(tx, ty) && g[tx][ty] != 'W') dfs(tx, ty);
}
}
int main()
{
//ios::sync_with_stdio(false);
cin >> n >> m;
int ans = 0;
for(int i = 1; i <= n; ++i)
scanf("%s", g[i] + 1);
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
if(!vis[i][j] && g[i][j] == 'L') ans++, dfs(i, j);
cout << ans << endl;
return 0;
}
后记
血的教训,开启 ios::sync_with_stdio(false);
语句之后,不能使用 (scanf, printf),否则会出错
(I. Mismatched Socks)
(J. Postman)
题意
一维数轴上分布了 (n) 个点,对应的坐标为 (x_{i}),所需要的邮件数量为 (m_{i})
邮递员每次从 (x = 0) 处出发,携带 (k) 个邮件,来回送货
请计算邮递员送完所有点需要的信所走的最短路
(1leq nleq 1000, 1leq k, |x_{i}|, m_{i}leq 10000000)
题解
贪心,正负点分开送,每次优先送最远的点,模拟即可
(code)
#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int, int>
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], "
"[i == r])
typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL MOD = 11092019;
const int inf = 0x3f3f3f3f;
const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
const int N = 1e3 + 7;
const double PI = acos(-1);
const double EPS = 1e-6;
using namespace std;
inline int read()
{
char c = getchar();
int ans = 0, f = 1;
while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
return ans * f;
}
LL n, k;
struct data
{
LL a, b;
data() {}
data(LL _a, LL _b) {a = _a, b = _b;}
bool operator < (const data &x) const {return a < x.a;}
}d1[N], d2[N];
LL getAns(data *d, int nn)
{
LL ans = 0;
for(int i = nn; i >= 1; --i) {
LL dis = 2LL * d[i].a;
LL num = d[i].b;
ans += (num / k) * dis;
if(num % k) {
ans += dis;
LL left = k - (num % k);
for(int j = i - 1; j >= 1; --j) {
if(d[j].b >= left) {d[j].b -= left; break;}
else left -= d[j].b, d[j].b = 0;
}
}
}
return ans;
}
int main()
{
scanf("%lld %lld", &n, &k);
int n1 = 0, n2 = 0;
for(int i = 1; i <= n; ++i) {
LL x, y;
scanf("%lld %lld", &x, &y);
if(x >= 0) d1[++n1] = data(x, y);
else d2[++n2] = data(-x, y);
}
sort(d1 + 1, d1 + 1 + n1);
sort(d2 + 1, d2 + 1 + n2);
LL ans1 = getAns(d1, n1);
LL ans2 = getAns(d2, n2);
cout << ans1 + ans2 << endl;
return 0;
}
/*
7 1
9400000 10000000
9500000 10000000
9600000 10000000
9700000 10000000
9800000 10000000
9900000 10000000
10000000 10000000
*/
(K. Six Sides)
题意
俩人掷俩六面骰子
- 若第一个人的点数大,那么第一个人获胜
- 若平局,继续抛
- 若第一个人的点数小,那么第一个人输、
计算第一个人赢的数学期望
题解
设 (a) 为玩家 (1) 点数大于玩家 (2) 点数的实验数
设 (b) 为玩家 (1) 点数小于玩家 (2) 点数的实验数
若 (a = b = 0),则 (E = 0),否则 (E = frac{a}{a + b})
(code)
#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int, int>
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], "
"[i == r])
typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL MOD = 11092019;
const int inf = 0x3f3f3f3f;
const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
const int N = 1e5 + 7;
const double PI = acos(-1);
const double EPS = 1e-6;
using namespace std;
inline int read()
{
char c = getchar();
int ans = 0, f = 1;
while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
return ans * f;
}
int a[10], b[10];
int main()
{
for(int i = 1; i <= 6; ++i) cin >> a[i];
for(int i = 1; i <= 6; ++i) cin >> b[i];
int cnt1 = 0, cnt2 = 0;
for(int i = 1; i <= 6; ++i) {
for(int j = 1; j <= 6; ++j) {
if(a[i] > b[j]) cnt1++;
else if(a[i] < b[j]) cnt2++;
}
}
if(cnt1 == cnt2 && !cnt1) puts("0.00000");
else printf("%.5f
", double(cnt1) / double(cnt1 + cnt2));
return 0;
}
(L. Three Square)
题意
给定 (3) 个长宽确定的长方形,判断是否可以组成一个正方形
题解
三个长方形中的最长边一定是正方形的边长,以此为依据分类讨论
一共 (6 imes(4 + 4) = 48) 种情况
(code)
#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int, int>
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], "
"[i == r])
typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL MOD = 11092019;
const int inf = 0x3f3f3f3f;
const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
const int N = 1e5 + 7;
const double PI = acos(-1);
const double EPS = 1e-6;
using namespace std;
inline int read()
{
char c = getchar();
int ans = 0, f = 1;
while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
return ans * f;
}
int a[10], b[10];
bool check1(int a1, int b1, int a2, int b2, int a3, int b3)
{
//cout << a1 << ' ' << b1 << ' ' << a2 << ' ' << b2 << ' ' << a3 << ' ' << b3 << endl;
return (a1 == a2 + a3 && b2 == b3 && a1 == b1 + b3 || a1 == a2 && a1 == a3 && a1 == b1 + b2 + b3);
}
int main()
{
int maxx = 0;
for(int i = 1; i <= 3; ++i) cin >> a[i] >> b[i], maxx = max(maxx, max(a[i], b[i]));
int f1 = 0, f2 = 0;
if(a[1] == maxx) {
f1 = check1(a[1], b[1], a[2], b[2], a[3], b[3]); f2 |= f1;
f1 = check1(a[1], b[1], a[2], b[2], b[3], a[3]); f2 |= f1;
f1 = check1(a[1], b[1], b[2], a[2], a[3], b[3]); f2 |= f1;
f1 = check1(a[1], b[1], b[2], a[2], b[3], a[3]); f2 |= f1;
}
if(b[1] == maxx) {
f1 = check1(b[1], a[1], a[2], b[2], a[3], b[3]); f2 |= f1;
f1 = check1(b[1], a[1], a[2], b[2], b[3], a[3]); f2 |= f1;
f1 = check1(b[1], a[1], b[2], a[2], a[3], b[3]); f2 |= f1;
f1 = check1(b[1], a[1], b[2], a[2], b[3], a[3]); f2 |= f1;
}
if(a[2] == maxx) {
f1 = check1(a[2], b[2], a[1], b[1], a[3], b[3]); f2 |= f1;
f1 = check1(a[2], b[2], a[1], b[1], b[3], a[3]); f2 |= f1;
f1 = check1(a[2], b[2], b[1], a[1], a[3], b[3]); f2 |= f1;
f1 = check1(a[2], b[2], b[1], a[1], b[3], a[3]); f2 |= f1;
}
if(b[2] == maxx) {
f1 = check1(b[2], a[2], a[1], b[1], a[3], b[3]); f2 |= f1;
f1 = check1(b[2], a[2], a[1], b[1], b[3], a[3]); f2 |= f1;
f1 = check1(b[2], a[2], b[1], a[1], a[3], b[3]); f2 |= f1;
f1 = check1(b[2], a[2], b[1], a[1], b[3], a[3]); f2 |= f1;
}
if(a[3] == maxx) {
f1 = check1(a[3], b[3], a[2], b[2], a[1], b[1]); f2 |= f1;
f1 = check1(a[3], b[3], a[2], b[2], b[1], a[1]); f2 |= f1;
f1 = check1(a[3], b[3], b[2], a[2], a[1], b[1]); f2 |= f1;
f1 = check1(a[3], b[3], b[2], a[2], b[1], a[1]); f2 |= f1;
}
if(b[3] == maxx) {
f1 = check1(b[3], a[3], a[2], b[2], a[1], b[1]); f2 |= f1;
f1 = check1(b[3], a[3], a[2], b[2], b[1], a[1]); f2 |= f1;
f1 = check1(b[3], a[3], b[2], a[2], a[1], b[1]); f2 |= f1;
f1 = check1(b[3], a[3], b[2], a[2], b[1], a[1]); f2 |= f1;
}
puts(f2 ? "YES" : "NO");
return 0;
}
/*
2 6
2 6
2 6
*/
(M. Zigzag)
题意
给定一个长度为 (50) 的序列,计算其中最长的 (zigzagging) 子序列
(zigzagging) 子序列定义为:递增递减交错的序列
例如:(1, 3, 2, 6, 5)
(nleq 50)
题解
类似于最长上升子序列
定义 (dp1[i]) 表示到第 (i) 位置为止,且第 (i) 位置为增长趋势的 (zigzagging subsequences) 的最长长度
定义 (dp2[i]) 表示到第 (i) 位置为止,且第 (i) 位置为下降趋势的 (zigzagging subsequences) 的最长长度
考虑状态转移
(code)
#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int, int>
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], "
"[i == r])
typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL MOD = 11092019;
const int inf = 0x3f3f3f3f;
const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
const int N = 1e5 + 7;
const double PI = acos(-1);
const double EPS = 1e-6;
using namespace std;
inline int read()
{
char c = getchar();
int ans = 0, f = 1;
while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
return ans * f;
}
int n, a[100], dp1[100], dp2[100];
int main()
{
ios::sync_with_stdio(false);
cin >> n;
for(int i = 1; i <= n; ++i) cin >> a[i];
int ans = 0;
for(int i = 1; i <= n; ++i){
dp1[i] = dp2[i] = 1;
for(int j = 1; j < i; ++j) {
if(a[j] > a[i]) dp1[i] = max(dp1[i], dp2[j] + 1);
if(a[j] < a[i]) dp2[i] = max(dp2[i], dp1[j] + 1);
}
}
for(int i = 1; i <= n; ++i) ans = max(ans, max(dp1[i], dp2[i]));
cout << ans << endl;
return 0;
}
(N. Paint)
题意
给定长为 (n) 的序列,以及 (k) 个子区间 ([a_{i}, b_{i}])
选取若干个不相交的子区间,使得未被覆盖的元素个数最少
(1leq nleq 10^{18}, 1leq kleq 200000)
题解
将 (k) 个区间按照右端点升序排序,左端点降序/升序排序
定义 (dp1[i]) 表示,以第 (i) 个区间为终点区间,所得到的最少的未被覆盖的元素个数
定义 (dp2[i] = maxleft{dp1[j], j < i ight})
考虑状态转移,二分查找最后一个区间 (j),使得 (b_{j} < a_{i})
则 (dp1[i] = max(dp1[i], dp2[j] + a_{i} - b_{i} + 1])
更新 (dp2[i] = max(dp2[i - 1], dp1[i]))
(code)
#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int, int>
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], "
"[i == r])
typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL MOD = 11092019;
const int inf = 0x3f3f3f3f;
const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
const int N = 2e5 + 7;
const double PI = acos(-1);
const double EPS = 1e-6;
using namespace std;
inline int read()
{
char c = getchar();
int ans = 0, f = 1;
while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
return ans * f;
}
LL n;
int k;
LL dp1[N], dp2[N];
struct node
{
LL L, R;
node() {}
node(LL _L, LL _R) {L = _L, R = _R;}
}d[N];
bool cmp(node x, node y)
{
if(x.R == y.R) return x.L > y.L;
return x.R < y.R;
}
int main()
{
scanf("%lld %d", &n, &k);
for(int i = 1; i <= k; ++i) {
LL x, y;
scanf("%lld %lld", &x, &y);
d[i] = node(x, y);
}
sort(d + 1, d + 1 + k, cmp);
for(int i = 1; i <= k; ++i) {
int p = lower_bound(d + 1, d + 1 + k, node(INF, d[i].L), cmp) - 1 - d;
dp1[i] = d[i].R - d[i].L + 1 + dp2[p];
dp2[i] = max(dp2[i - 1], dp1[i]);
}
//for(int i = 1; i <= k; ++i)
//cout << d[i].L << ' ' << d[i].R << ' ' << dp1[i] << ' ' << dp2[i] << endl;
LL ans = INF;
for(int i = 1; i <= k; ++i) ans = min(ans, n - dp1[i]);
cout << ans << endl;
return 0;
}
/*
15 5
1 4
5 6
6 8
8 12
12 15
*/
后记
在结构体数组里面用 lower_bound
需要使用第四个参数,自定义 cmp
比较函数,这是一个新姿势
(O. Shopping)
题意
有 (n) 个货物,每个货物有无限多个,价格为 (a_{i})
有 (q) 个客户,每人有 (v_{i}) 的资金,他们从 (l_{i}) 逛到 (r_{i}),对于每一种货物,他们都会买到买不起为止
请计算每人剩余的资金
(1leq n, qleq 200000, 1leq a_{i}, v_{i}leq 10^{18}, 1leq l_{i}, r_{i}leq n)
思路
记当前在 (pos) 位置,资金还剩余 (x)
问题等价于在 ([pos, r_{i}]) 内寻找第一个不大于 (x) 的位置
由于是无序序列,考虑用线段树求解,复杂度套个 (log_{2}{n})
由于取模操作,每次购买物品资金至少减少一半,所以最多购买 (log_{2}v_{i}) 件物品
总的复杂度为 (O(qlognlogv_{i}))
(code)
#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int, int>
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], "
"[i == r])
typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL MOD = 11092019;
const int inf = 0x3f3f3f3f;
const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
const int N = 2e5 + 7;
const double PI = acos(-1);
const double EPS = 1e-6;
using namespace std;
inline int read()
{
char c = getchar();
int ans = 0, f = 1;
while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
return ans * f;
}
LL n, q, a[N];
struct node
{
LL l, r, minn;
}t[N * 4];
void pushup(int rt)
{
t[rt].minn = min(t[rt * 2].minn, t[rt * 2 + 1].minn);
}
void build(int L, int R, int rt){
t[rt].l = L, t[rt].r = R;
if(L == R){
t[rt].minn = a[L];
return;
}
int mid = (L + R) / 2;
build(L, mid, rt * 2);
build(mid + 1, R, rt * 2 + 1);
pushup(rt);
}
int query(int L, int R, LL val, int rt)
{
//cout << L << ' ' << R << endl;
if(t[rt].l == t[rt].r){
if(t[rt].minn <= val) return t[rt].l;
else return -1;
}
int mid = (t[rt].l + t[rt].r) / 2;
int ans = -1;
if(L <= mid && t[rt * 2].minn <= val) {
ans = query(L, R, val, rt * 2);
if(ans == -1){
if(mid < R && t[rt * 2].minn <= val) ans = query(L, R, val, rt * 2 + 1);
}
return ans;
}
else if(mid < R && t[rt * 2 + 1].minn <= val) return query(L, R, val, rt * 2 + 1);
return -1;
}
int main()
{
scanf("%lld %lld", &n, &q);
for(int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
build(1, n, 1);
while(q--) {
LL m;
int L, R;
scanf("%lld %d %d", &m, &L, &R);
int p = L;
while(1) {
m %= a[p];
p = query(p + 1, R, m, 1);
if(p == -1) break;
}
cout << m << endl;
}
return 0;
}
/*
5 3
5 3 2 4 6
107 1 4
*/
后记
也可以使用单调栈求解,回头再思考一下