「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. iOS悬浮窗口(无论界面跳转、View始终在视图上显示,可移动)

    2016.09.24 23:52* 字数 71 阅读 5925评论 9喜欢 11 让所有界面都显示,最好还是封装一个继承Window的类:JYCWindow. 先看看效果:   mygif.gif 关 ...

  2. java中的定时任务小示例

    package package_1; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Timer; ...

  3. IdentityServer4【Introduction】之概括

    The Big Picture 大多数现代应用看起来都像下面的样子: 大多数的交互是下面这样: 浏览器与web应用之间的通信 web应用和web APIs之间的通信(这两者有时是独立的,有时是有用户参 ...

  4. [转帖]利用hydra(九头蛇)暴力破解内网windows登录密码

    利用hydra(九头蛇)暴力破解内网windows登录密码 https://blog.csdn.net/weixin_37361758/article/details/77939070 尝试了下 能够 ...

  5. 日期选择器date、week、time、datetime、datetime-local类型

    下面只写两个类型的代码案例,其他都大同小异 date类型: <!DOCTYPE html> <html> <head> <meta charset=" ...

  6. mysql 数据库的主从同步

    1.复制准备 操作系统 centOS 主库(mysql master):  ip为123.56.94.1   port为3306  mysql 版本 5.7.16 从库(mysql slave):   ...

  7. PHP超级全局变量、魔术变量和魔术函数

    PHP超级全局变量(9个) $GLOBALS 储存全局作用域中的变量 $_SERVER 获取服务器相关信息 $_REQUEST 获取POST和GET请求的参数 $_POST 获取表单的POST请求参数 ...

  8. jedis集群版应用

    1.pom文件添加依赖: 2.创建配置文件 <!-- jedis集群版配置(JedisCluster通过构造传参(2个参数)) --> <bean id="redisCli ...

  9. faster rcnn讲解很细

    https://blog.csdn.net/bailufeiyan/article/details/50749694 https://www.cnblogs.com/dudumiaomiao/p/65 ...

  10. 了解AutoCAD对象层次结构 —— 1 ——应用程序

    想象这样一个场景:当您开始一天的工作,坐到电脑前面,用鼠标双击桌面上的AutoCAD Civil 3D图标,这时一个AutoCAD Civil 3D应用程序将运行起来.打开Windows任务管理器,我 ...