\(ACM\) 期末考试
- $ACM$ 期末考试
- $A.\ Alphabet$
- 题意
- 题解
- $code$
- $B.\ Barbells$
- 题意
- 题解
- $code$
- $C,\ Buggy\ Robot$
- 题意
- 题解
- $code$
- 后记
- $D.\ Cameras$
- 题意
- 题解
- $code$
- $E.\ Contest Score$
- 题意
- 题解
- $code$
- $F.\ Equality$
- 题意
- 题解
- $code$
- $G.\ Gravity$
- 题意
- 题解
- $code$
- $H.\ Islands$
- 题意
- 题解
- $code$
- 后记
- $I.\ Mismatched\ Socks$
- $J.\ Postman$
- 题意
- 题解
- $code$
- $K.\ Six Sides$
- 题意
- 题解
- $code$
- $L.\ Three\ Square$
- 题意
- 题解
- $code$
- $M.\ Zigzag$
- 题意
- 题解
- $code$
- $N.\ Paint$
- 题意
- 题解
- $code$
- 后记
- $O.\ Shopping$
- 题意
- 思路
- $code$
- 后记
- $P.\ Contest\ Strategy$
- $A.\ Alphabet$
\(A.\ Alphabet\)
题意
给定一个由小写字母组成的字符串 \(s\),可以在任意位置插入任意数量的小写字母
计算最少插入多少小写字母,使得新字符串 \(s'\) 中含有子序列 abcdefghijklmnopqrstuvwxyz
\(|s| < 50\)
题解
即求字符串中的最长上升子序列
定义 \(dp[i]\) 为到 \(i\) 位置所具备的最长上升子序列,则 \(dp[i] = max\left\{dp[j] + 1,\ j < i\right\}\)
\(O(n^2)\) 暴力转移
\(code\)
#include
#define fi first
#define se second
#define pii pair
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " \n"[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] <
\(B.\ Barbells\)
题意
有 \(n\) 个杠铃和 \(m\) 个杠铃片,\(n,\ m\leq 14\)
在满足杠铃两端重量一致的前提下,计算这些器件一共可以组和出多少种不同的重量
题解
双重二进制枚举杠铃片的选则,\(check\) 重量是否一致,用与运算判断是否为独立集合即可
\(code\)
#include
#define fi first
#define se second
#define pii pair
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " \n"[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 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 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\times 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
#define fi first
#define se second
#define pii pair
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " \n"[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 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\n", ans);
return 0;
}
后记
感觉这题相当难想,也相当难写,需要仔细体会
\(D.\ Cameras\)
题意
有 \(n\) 个房子,其中 \(k\) 个房子有灯
现在要求每 \(r\) 个连续房子至少得有两个房子有灯,计算需要增加的灯的个数
\(n\leq 100000,\ 0\leq k\leq n\)
题解
贪心,优先往右边的房子放灯
嵌套循环寻找右边第一个没有灯的位置,该位置灯的数量加一,注意这个嵌套循环最多循环三次,复杂度最多带个常数 \(3\)
要求快速查询区间内灯的个数,以及单点修改,所以考虑用树状数组进行维护
\(code\)
#include
#define fi first
#define se second
#define pii pair
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " \n"[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\)
假设读题不花费时间,输出罚时
\(1\leq k\leq n\leq 300,\ 1\leq t_{i}\leq 1000000\)
题解
签到,优先队列模拟即可
\(code\)
#include
#define fi first
#define se second
#define pii pair
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " \n"[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, greater > 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
#define fi first
#define se second
#define pii pair
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " \n"[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\times m\) 的二维格点图,模拟苹果受重力的掉落情况
\(1\leq n,\ m\leq 50\)
题解
签到,模拟即可
\(code\)
#include
#define fi first
#define se second
#define pii pair
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " \n"[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\n", g[i] + 1);
return 0;
}
\(H.\ Islands\)
题意
给定一个 \(n\times m\) 的二维格点图,\(L\) 表示陆地,\(W\) 表示海洋,\(C\) 表示云朵,云朵既可以变成海洋也可以变成陆地
恰当地变换 \(C\) 的形态,计算图中最少有多少陆地连通块
\(1\leq n,\ m\leq 50\)
题解
把所有与 \(L\) 相连通的 \(C\) 全部变成 \(L\),因为这样连通块个数才不会增加
\(dfs\) 即可
\(code\)
#include
#define fi first
#define se second
#define pii pair
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " \n"[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\) 个邮件,来回送货
请计算邮递员送完所有点需要的信所走的最短路
\(1\leq n\leq 1000,\ 1\leq k,\ |x_{i}|,\ m_{i}\leq 10000000\)
题解
贪心,正负点分开送,每次优先送最远的点,模拟即可
\(code\)
#include
#define fi first
#define se second
#define pii pair
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " \n"[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
#define fi first
#define se second
#define pii pair
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " \n"[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\n", double(cnt1) / double(cnt1 + cnt2));
return 0;
}
\(L.\ Three\ Square\)
题意
给定 \(3\) 个长宽确定的长方形,判断是否可以组成一个正方形
题解
三个长方形中的最长边一定是正方形的边长,以此为依据分类讨论
一共 \(6\times(4 + 4) = 48\) 种情况
\(code\)
#include
#define fi first
#define se second
#define pii pair
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " \n"[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\)
\(n\leq 50\)
题解
类似于最长上升子序列
定义 \(dp1[i]\) 表示到第 \(i\) 位置为止,且第 \(i\) 位置为增长趋势的 \(zigzagging\ subsequences\) 的最长长度
定义 \(dp2[i]\) 表示到第 \(i\) 位置为止,且第 \(i\) 位置为下降趋势的 \(zigzagging\ subsequences\) 的最长长度
考虑状态转移
\(code\)
#include
#define fi first
#define se second
#define pii pair
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " \n"[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}]\)
选取若干个不相交的子区间,使得未被覆盖的元素个数最少
\(1\leq n\leq 10^{18},\ 1\leq k\leq 200000\)
题解
将 \(k\) 个区间按照右端点升序排序,左端点降序/升序排序
定义 \(dp1[i]\) 表示,以第 \(i\) 个区间为终点区间,所得到的最少的未被覆盖的元素个数
定义 \(dp2[i] = max\left\{dp1[j],\ j < i\right\}\)
考虑状态转移,二分查找最后一个区间 \(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
#define fi first
#define se second
#define pii pair
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " \n"[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}\),对于每一种货物,他们都会买到买不起为止
请计算每人剩余的资金
\(1\leq n,\ q\leq 200000,\ 1\leq a_{i},\ v_{i}\leq 10^{18},\ 1\leq l_{i},\ r_{i}\leq n\)
思路
记当前在 \(pos\) 位置,资金还剩余 \(x\)
问题等价于在 \([pos,\ r_{i}]\) 内寻找第一个不大于 \(x\) 的位置
由于是无序序列,考虑用线段树求解,复杂度套个 \(log_{2}{n}\)
由于取模操作,每次购买物品资金至少减少一半,所以最多购买 \(log_{2}v_{i}\) 件物品
总的复杂度为 \(O(qlognlogv_{i})\)
\(code\)
#include
#define fi first
#define se second
#define pii pair
#define pb push_back
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " \n"[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
*/
后记
也可以使用单调栈求解,回头再思考一下