「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. IP核引发的关于定,浮点数的认识

    上面是一段关于CORDIC_IP测试文件,用于计算给定角度的sin值和cos值,关于数值表示规则在此不再重复,仅仅说明以下3点: 1  数采用原码,反码,补码,本身并没有正确与否之分(这一点很重要,我 ...

  2. hadoop:如何运行自带wordcount

    1.在linux系统创建文件 vi aa.txt   --------i 进行编辑  输入  内容(多个单词例如:aa bb cc aa) 2.在HDFS上面创建文件夹 hdfs dfs -mkdir ...

  3. http1.0 1.1 与2.0

    长连接 HTTP 1.0需要使用keep-alive参数来告知服务器端要建立一个长连接,而HTTP1.1默认支持长连接. HTTP是基于TCP/IP协议的,创建一个TCP连接是需要经过三次握手的,有一 ...

  4. C# web发布设置

    1.配置文件设置: 选择"自定义",配置文件框自己输入. 2.连接设置: 3.发布版本设置 4.预览 预览没问题点发布即可.

  5. 解决多人开发时使用window.onload的覆盖问题

    通用型小函数:解决多人开发时,同时使用window.onload事件所出现的后面的window.onload函数覆盖前面一个window.onload函数的问题. function addLoadEv ...

  6. Linux 下面RPM 安装的SQLSERVER 修改字符集的方法

    1. 自己还是太low 2. 遇到问题 先 -h 处理 3. 发现登录报错, 怀疑是字符集的问题: 4. 计划是修改字符集 到 自己的环境可用的状态 使用命令 /opt/mssql/bin/mssql ...

  7. STL 序列容器

    转自时习之 STL中大家最耳熟能详的可能就是容器,容器大致可以分为两类,序列型容器(SequenceContainer)和关联型容器(AssociativeContainer)这里介绍STL中的各种序 ...

  8. Baby-Step-Giant-Step 很酷的算法

    Baby-Step-Giant-Step BSGS算法用于解决形如:      A  ^  x  ≡  B  (  mod  C  ) 的问题.  学这个算法前需要具备以下知识:快速幂取模.扩展欧几里 ...

  9. C# Note4:XML序列化和反序列化(含加密解密等)

    前言 在项目中,我们经常用到各种配置文件,比如xml文件.binary文件等等,这里主要根据实践经验介绍下xml文件的序列化和反序列化(毕竟最常用). 实践背景:我要做一个用户管理功能,用户账号信息存 ...

  10. java日志框架之logback(一)——logback工程简介

    Logback工程 致力于成为log4j工程的继承者 Logback的架构足够泛型化,故能够应用于许多不同的环境.当前,logback划分为三个组件: logback-core logback-cla ...