「SCOI2016」妖怪

题意

有 \(n\) 只妖怪,每只妖怪有攻击力 \(\text{atk}\) 和防御力 \(\text{dnf}\) ,在环境 \((a, b)\) 下,它可以把攻击力和防御力以 \(a : b\) 的代价呼唤,它的最强战斗力为互换后的攻击力与防御力的最大值。

现要给他们一种环境,使得它们的最强战斗力最小。答案保留四位小数。

\(1 \le n \le 10^6, 0 < \text{atk}, \text{dnf} \le 10^6\)

题解

首先,一个很显然的性质,如果把一只妖怪的两个属性看做二维平面上的一个点,那么在某一环境下妖怪的战斗力,也就是过这个点的某一条直线与 \(x\) 轴和 \(y\) 轴交点坐标之和。

于是题目所求就可以转化为,给定二位平面内的 \(n\) 个点,确定一个直线的斜率,使得分别过这 \(n\) 个点的 \(n\) 条直线的横纵坐标之和最大的直线尽可能小。

我们猜测一下,它其实关于斜率的函数图像是凸的,那么就是可以三分的,我们直接三分最值就好啦QAQ 复杂度是 \(O(n \log \epsilon^{-1})\) 的,特别好写。

为啥呢?

对于每一项展开得到 \(\text{atk}+\frac{\text{dnf}}{b}a + \text{dnf} + \frac{\text{atk}}{a} b\)

令 \(T=\frac{a}{b}\) 那么原式 \(=\text{atk}+T\text{dnf} + \text{dnf} + \frac{\text{atk}}{T}\) 这就是那个单峰的对勾函数, 把单峰函数复合为求最大值,发现也是个单峰函数,其实就是个凸的。

前面直接三分常数还是挺大的,我们有更好的做法。

于是我们可以先求出凸包,那么对答案造成贡献的点一定在凸包上。前面说了这个是对勾函数。于是我们分类讨论出函数的最小值即可。时间复杂度 \(O(n \log n)\) 。

总结

遇到计算几何最优化的题。首先猜测凸性,然后三分。实在不行,再猜测可用点在凸包上,然后就方便讨论。

代码

三分

#include <bits/stdc++.h>

#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl
#define DEBUG(...) fprintf(stderr, __VA_ARGS__) using namespace std; template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return b > a ? a = b, 1 : 0; } inline int read() {
int x(0), sgn(1); char ch(getchar());
for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
return x * sgn;
} void File() {
#ifdef zjp_shadow
freopen ("2015.in", "r", stdin);
freopen ("2015.out", "w", stdout);
#endif
} const double eps = 1e-13; const int N = 1e6 + 1e3; int n, atk[N], def[N]; inline double f(double k) {
double ans = .0;
For (i, 1, n)
chkmax(ans, atk[i] + def[i] - (k * atk[i] + def[i] / k));
return ans;
} int main () { File(); n = read();
For (i, 1, n)
atk[i] = read(), def[i] = read(); double l = - 5, r = 0;
while (r - l > eps) {
double mid1 = (l + r) / 2.0,
mid2 = (mid1 + r) / 2.0;
if (f(mid1) < f(mid2)) r = mid2; else l = mid1;
}
printf ("%.4lf\n", f(l)); return 0; }

凸壳

#include <bits/stdc++.h>

#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl
#define DEBUG(...) fprintf(stderr, __VA_ARGS__) using namespace std; typedef long long ll; template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return b > a ? a = b, 1 : 0; } inline int read() {
int x(0), sgn(1); char ch(getchar());
for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
return x * sgn;
} void File() {
#ifdef zjp_shadow
freopen ("2015.in", "r", stdin);
freopen ("2015.out", "w", stdout);
#endif
} const double eps = 1e-10, inf = 1e10; const int N = 1e6 + 1e3; struct Point {
int x, y;
inline double Min() {
return x + y + 2 * sqrt(1ll * x * y);
}
inline double f(double k) {
chkmin(k, -eps);
return x + y - (x * k + y / k);
}
}; inline Point operator - (const Point &lhs, const Point &rhs) {
return (Point) {lhs.x - rhs.x, lhs.y - rhs.y};
} double Slope (const Point &lhs, const Point &rhs) {
if (lhs.x == rhs.x) return inf;
return 1.0 * (rhs.y - lhs.y) / (rhs.x - lhs.x);
} inline ll Cross(Point a, Point b) { return 1ll * a.x * b.y - 1ll * a.y * b.x; } struct Cmp {
inline bool operator () (const Point &lhs, const Point &rhs) const {
return lhs.x != rhs.x ? lhs.x < rhs.x : lhs.y < rhs.y;
}
}; Point P[N], stk[N]; int top; inline bool Check(Point a, Point b, Point c) { return Cross(c - a, b - a) <= 0; } int main () { File(); int n = read();
For (i, 1, n)
P[i].x = read(), P[i].y = read();
sort(P + 1, P + n + 1, Cmp()); stk[top = 1] = P[1];
stk[top = 2] = P[2]; For (i, 3, n) {
while (top > 1 && Check(stk[top - 1], stk[top], P[i])) -- top;
stk[++ top] = P[i];
} double ans = inf;
For (i, 1, top) {
double pre = i > 1 ? Slope(stk[i - 1], stk[i]) : eps, suf = i < top ? Slope(stk[i], stk[i + 1]) : - inf;
chkmin(pre, .0); chkmin(suf, .0);
double res = min(stk[i].f(pre), stk[i].f(suf)), Best = - sqrt(1.0 * stk[i].y / stk[i].x);
if (suf < Best && Best < pre) chkmin(res, stk[i].Min()); chkmin(ans, res);
}
printf ("%.4lf\n", ans); return 0; }

「SCOI2016」美味

题意

有一个长度为 \(n\) 的序列 \(\{a_i\}\) 。

有 \(q\) 次询问,每次四个整数 \(b, x, l, r\) ,可以把 \(b\) 变成 \(b \text{ xor } (a_i + x)\) (只能变一次),其中 \(i \in [l, r]\) ,问 \(b\) 的最大值。

$ 1 \leq n \leq 2 \times 10 ^ 5, 0 \leq a_i, b_i, x_i < 10 ^ 5, 1 \leq m \leq 10 ^ 5 $

题解

如果 \(x = 0\) 那么就是区间 \(01-Trie\) 套 std :: set 啦。

但是有 \(x\) 怎么做呢?其实还是可以类似于 \(01-Trie\) 。

我们按位考虑,我们从高到低考虑,看 \(b\) 的每一位是否能异或出 \(1\) 。

不难发现,当前的询问会对到一道连续区间 \([l, r]\) 。

这下问题就转化为,区间查询权值在一段区间内的数是否存在,这个直接用主席树维护即可。

复杂度是 \(O(n \log n \log a_i)\) 的。

总结

可以考虑用数据结构去模拟另外一个数据结构。

代码

#include <bits/stdc++.h>

#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl
#define DEBUG(...) fprintf(stderr, __VA_ARGS__) using namespace std; template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return b > a ? a = b, 1 : 0; } inline int read() {
int x(0), sgn(1); char ch(getchar());
for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
return x * sgn;
} void File() {
#ifdef zjp_shadow
freopen ("2016.in", "r", stdin);
freopen ("2016.out", "w", stdout);
#endif
} const int N = 2e5 + 1e3; template<int Maxn>
struct ChairMan_Tree { int tot[Maxn], ls[Maxn], rs[Maxn], Size = 0; inline void Update(int &o, int pre, int l, int r, int up) {
tot[o = ++ Size] = tot[pre] + 1;
ls[o] = ls[pre]; rs[o] = rs[pre]; if (l == r) return ;
int mid = (l + r) >> 1;
if (up <= mid) Update(ls[o], ls[pre], l, mid, up);
else Update(rs[o], rs[pre], mid + 1, r, up);
} bool Query(int x, int y, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) return tot[y] - tot[x];
int mid = (l + r) >> 1;
if (ql <= mid && Query(ls[x], ls[y], l, mid, ql, qr)) return true;
if (qr > mid && Query(rs[x], rs[y], mid + 1, r, ql, qr)) return true;
return false;
} }; ChairMan_Tree<int(4 * N * log2(N))> T; int n, m, rt[N], a[N]; int main () { File(); n = read(); m = read(); For (i, 1, n) a[i] = read();
int lim = *max_element(a + 1, a + n + 1); For (i, 1, n)
T.Update(rt[i], rt[i - 1], 0, lim, a[i]); while (m --) {
int b = read(), x = read(), l = read() - 1, r = read();
int len = ceil(log2(max(b, lim + x))), ans = 0; Fordown (i, len, 0) {
int need = ((b >> i) & 1) ^ 1, L, R;
L = ans + (need << i) - x;
R = ans + (1 << i + need) - 1 - x;
ans |= (!need ^ (L <= lim && R >= 0 && T.Query(rt[l], rt[r], 0, lim, L, R))) << i;
}
printf ("%d\n", ans ^ b); } return 0; }

「SCOI2016」围棋

题意

有 \(q\) 次询问,每次给你一个 \(2 \times c\) 的模板,问有多少个 \(n \times m\) 只包含 W, B, X 的棋盘至少包含一个模板。

$ n \leq 100, m \leq 12, c \leq 6, q \leq 5 $

题解

\(m\) 很小,显然是考虑轮廓线 \(dp\) 。

一个很直观的想法是记下连续两行上的状态,直接做,复杂度是 \(O(qnm3^{2m})\) 的,显然过不去啦。

其实很多状态是没有意义的,我们只需要记上面一圈轮廓线的对应的结尾是否能匹配上 \(S_1\) 即可。我们模板上面一排为 \(S_1\) 下面一排为 \(S_2\) 。

然后这样状态显然还不够,因为你无法去转移到后面的状态,对于匹配问题我们只需要多记下最后一个位置匹配到最远的字符就好啦,然后转移就用 \(\text{KMP}\) 去转。

具体来说,令 f[i][j][S][x][y] 为到 \(i\) 行 \(j\) 列,轮廓线能匹配上的状态为 \(S\) ,\((i, j)\) 结尾的串匹配到 \(S_1\) 的第 \(x\) 位,\(S_2\) 的第 \(y\) 位。

其实状态没有那么满,用个哈希表转移一下,跑的挺快的。复杂度是 \(O(nm2^{m}c^2)\) 。

总结

dp 一定要记得压状态鸭!!

代码

至于实现,可以记不合法的方案数,最后用 \(3^{nm}\) 减掉即可。其实记合法的也一样。。。

#include <bits/stdc++.h>

#define For(i, l, r) for (register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for (register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Rep(i, r) for (register int i = (0), i##end = (int)(r); i < i##end; ++i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl using namespace std; template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return b > a ? a = b, 1 : 0; } inline int read() {
int x(0), sgn(1); char ch(getchar());
for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
return x * sgn;
} void File() {
#ifdef zjp_shadow
freopen ("2017.in", "r", stdin);
freopen ("2017.out", "w", stdout);
#endif
} const int N = 13, Mod = 1e9 + 7; int n, m, c, q; inline int encode(int S, int x, int y) {
return S * (c + 1) * (c + 1) + x * (c + 1) + y;
} inline void decode(int code, int &S, int &x, int &y) {
S = code / (c + 1) / (c + 1);
x = code / (c + 1) % (c + 1);
y = code % (c + 1);
} unordered_map<int, int> M[2]; char S1[N], S2[N]; int fail1[N], fail2[N]; inline void get_fail(char *S, int *fail) {
fail[1] = 0;
For (i, 2, strlen(S + 1)) {
int j = fail[i - 1];
while (j && S[j + 1] != S[i]) j = fail[j];
fail[i] = j + (S[i] == S[j + 1]);
}
} inline int kmp(char *S, int *fail, int pos, char T) {
while (pos && S[pos + 1] != T) pos = fail[pos];
return pos + (S[pos + 1] == T);
} inline void Add(int &a, int b) {
if ((a += b) >= Mod) a -= Mod;
} int cur;
inline void Insert(int S, int x, int y, int val) {
Add(M[cur][encode(S, x, y)], val);
} char ch[3] = {'W', 'B', 'X'}; int main() { File(); n = read(); m = read(); c = read(); q = read(); while (q --) { scanf ("%s", S1 + 1); get_fail(S1, fail1);
scanf ("%s", S2 + 1); get_fail(S2, fail2); M[0].clear(); M[1].clear(); cur = 1; Insert(0, 0, 0, 1); cur ^= 1; int ans = 0;
For (i, 1, n) For (j, 1, m) {
for (auto it : M[cur ^ 1]) {
int S, x, y, val = it.second;
decode(it.first, S, x, y);
Rep (k, 3) {
int nx = kmp(S1, fail1, x, ch[k]);
int ny = kmp(S2, fail2, y, ch[k]);
if ((S & 1) && ny == c) continue;
int nS = (S >> 1) | ((nx == c) << (m - 1));
if (j == m) {
nx = ny = 0;
if (i == n) Add(ans, val);
}
Insert(nS, nx, ny, val);
}
}
M[cur ^= 1].clear();
} int res = 1;
For (i, 1, n * m) res = res * 3ll % Mod;
printf ("%d\n", (res - ans + Mod) % Mod); } return 0; }

SCOI2016 Day2 简要题解的更多相关文章

  1. SCOI2016 Day1 简要题解

    目录 「SCOI2016」背单词 题意 题解 代码 「SCOI2016」幸运数字 题意 题解 总结 代码 「SCOI2016」萌萌哒 题意 题解 总结 代码 「SCOI2016」背单词 题意 这出题人 ...

  2. JLOI2015 DAY2 简要题解

    「JLOI2015」骗我呢 题意 问有多少个 \(n \times m\) 的矩阵 \(\{x_{i, j}\}\) 满足 对于 \(\forall i \in [1, n], j \in [1, m ...

  3. SCOI 2015 Day2 简要题解

    「SCOI2015」小凸玩密室 题意 小凸和小方相约玩密室逃脱,这个密室是一棵有 $ n $ 个节点的完全二叉树,每个节点有一个灯泡.点亮所有灯泡即可逃出密室.每个灯泡有个权值 $ A_i $,每条边 ...

  4. AHOI2013 Round2 Day2 简要题解

    第一题: 第一问可以用划分树或主席树在O(nlog2n)内做出来. 第二问可以用树状数组套主席树在O(nlog2n)内做出来. 我的代码太挫了,空间刚刚卡过...(在bzoj上) 第二题: 分治,将询 ...

  5. Noip 2014酱油记+简要题解

    好吧,day2T1把d默认为1也是醉了,现在只能期待数据弱然后怒卡一等线吧QAQ Day0 第一次下午出发啊真是不错,才2小时左右就到了233,在车上把sao和fate补掉就到了= = 然后到宾馆之后 ...

  6. Tsinghua 2018 DSA PA2简要题解

    反正没时间写,先把简要题解(嘴巴A题)都给他写了记录一下. upd:任务倒是完成了,我也自闭了. CST2018 2-1 Meteorites: 乘法版的石子合并,堆 + 高精度. 写起来有点烦貌似. ...

  7. Codeforces 863 简要题解

    文章目录 A题 B题 C题 D题 E题 F题 G题 传送门 简要题解?因为最后一题太毒不想写了所以其实是部分题解... A题 传送门 题意简述:给你一个数,问你能不能通过加前导000使其成为一个回文数 ...

  8. HNOI2018简要题解

    HNOI2018简要题解 D1T1 寻宝游戏 题意 某大学每年都会有一次 Mystery Hunt 的活动,玩家需要根据设置的线索解谜,找到宝藏的位置,前一年获胜的队伍可以获得这一年出题的机会. 作为 ...

  9. JXOI2018简要题解

    JXOI2018简要题解 T1 排序问题 题意 九条可怜是一个热爱思考的女孩子. 九条可怜最近正在研究各种排序的性质,她发现了一种很有趣的排序方法: Gobo sort ! Gobo sort 的算法 ...

随机推荐

  1. 蒲公英App开发之检测新版本

    https://www.jianshu.com/p/2d3f048511d7 2017.04.17 16:22* 字数 62 阅读 422评论 0喜欢 1 可以在App内部实现检测版本更新并实现安装. ...

  2. Python_匿名函数

    匿名函数:为了解决那些功能很简单的需求而设计的一句话函数. 代码如下: 1 正常函数: 2 3 def calc(n): 4 5 return n ** n 6 7 print(calc(10)) 8 ...

  3. Python之自测代码标识__name__=='__main__'

    __name__是python的默认的自测代码标识,其他文件导入该python文件时,不会执行这行代码以下部分. def yangfan(a): print('yangfan %s' %a) prin ...

  4. PHP安装pecl扩展--通用

    虽然现在composer很流行,但是有时候,我们还是要安装pecl的扩展. pecl扩展可以在pecl.php.net中查看,想要什么扩展,可以去搜索,比如xdebug.siege.memcached ...

  5. 网站之robots.txt文件

    一.robots.txt是什么?   robots.txt是一个纯文本文件,在这个文件中网站管理者可以声明该网站中不想被搜索引擎访问的部分,或者指定搜索引擎只收录指定的内容. 当一个搜索引擎(又称搜索 ...

  6. Oracle 内存参数调优设置

    Oracle 数据库系统中起到调节作用的参数叫初始化参数,数据库管理员根据实际情况需要适当调整这些 初始化参数以优化Oracle系统. 1 主要系统参数调优介绍 2 系统内存参数的分配 2.1 Ora ...

  7. CIFS 与 SMB 有什么区别?

    CIFS 与 SMB 有什么区别? https://www.getnas.com/2018/11/30/cifs-vs-smb/ 网络协议 一知半解 学习一下挺好的.. 记得 win2019 已经废弃 ...

  8. Linux基础学习笔记6-SHELL编程

    编程基础 程序:指令+数据 程序编程风格: 过程式:以指令为中心,数据服务于指令 对象式:以数据为中心,指令服务于数据 shell程序:提供了编程能力,解释执行 编程基本概念: 顺序执行:循环执行:选 ...

  9. hadoop第一个例子

    Java.io.URL 1.编写java程序 package com.company; import java.io.IOException; import java.io.InputStream; ...

  10. scrapy架构简介

    一.scrapy架构介绍 1.结构简图: 主要组成部分:Spider(产出request,处理response),Pipeline,Downloader,Scheduler,Scrapy Engine ...