「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. 查看mysql数据库连接数、并发数相关信息

    查看mysql数据库连接数.并发数相关信息. - caodongfang126的博客 - CSDN博客 https://blog.csdn.net/caodongfang126/article/det ...

  2. 配置nginx反向代理服务器,解决浏览器跨域调用接口的限制问题

    配置nginx反向代理服务器,解决浏览器跨域调用接口的限制问题 - 大venn的博客 - CSDN博客https://blog.csdn.net/u011135260/article/details/ ...

  3. java lang(Comparable接口) 和java util(Comparator接口)分析比较

    //Comparable 接口强行对实现它的每个类的对象进行整体排序. -- 自然排序.类的compareTo称为自然比较方法. public interface Comparable<T> ...

  4. java lang(ClassLoader)

    一.什么是ClassLoader? 大家都知道,当我们写好一个Java程序之后,不是管是CS还是BS应用,都是由若干个.class文件组织而成的一个完整的Java应用程序,当程序在运行时,即会调用该程 ...

  5. hive权限配置

    基于CDH5.x的Hive权限配置 1.打开权限控制,默认是没有限制的 set hive.security.authorization.enabled=true; 2.配置默认权限 hive.secu ...

  6. maven中jar下载失败

    关键词:maven jar 错误描述:反编译时遇到 invalid LOC header (bad signature)的问题 aether-89969cb8-5741-44e3-be2c-74f90 ...

  7. flutter图片铺满父框

    正常我们需要显示一张图片,会用到Image这个控件. 打个比方,我们加载一张本地的图片, 先看一下这个Image.asset的源码: Image.asset(String name, { Key ke ...

  8. 用 Python 写一个多进程兼容的 TimedRotatingFileHandler

    我前面有篇文章已经详细介绍了一下 Python 的日志模块.Python 提供了非常多的可以运用在各种不同场景的 Log Handler. TimedRotatingFileHandler 是 Pyt ...

  9. Python魔法方法(magic method)细解几个常用魔法方法(下)

    接上文,再介绍最后几个常用的魔法方法. 关于__dict__: 先上个例子: class Test(object): fly = True def __init__(self, age): self. ...

  10. CSS3圆角详解(border-radius)

    1.CSS3圆角的优点 传统的圆角生成方案,必须使用多张图片作为背景图案.CSS3的出现,使得我们再也不必浪费时间去制作这些图片了,而且还有其他多个优点: 减少维护的工作量.图片文件的生成.更新.编写 ...