「JSOI2013」贪心的导游

「JSOI2013」贪心的导游

传送门

多次询问区间内%一个数的最大值 我们不妨设这个数为M_sea

值域比较小所以考虑分块维护。

我们观察到对于给定的一个 \(p\) ,函数 \(y = x \% p\) 是分段的且在各段内递增,所以我们可以先分块,记一下每个块内小于等于某个数的最大值,记为 \(g_i\) ,那么我们显然是要在所有的 \(i = kp - 1, k \ge 1\) 中查询 \(g_i\) 并减掉会被 % 掉的部分,那么我们就可以预处理出一个块内的答案了,然后查询的时候暴力查就是了。

#include <cstring>
#include <cstdio>
#include <cmath>
#define rg register
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
template < class T > inline void swap(T& a, T& b) { T t = a; a = b; b = t; }
template < class T > inline T max(T a, T b) { return a > b ? a : b; }
template < class T > inline void read(T& s) {
    s = 0; int f = 0; char c = getchar();
    while ('0' > c || c > '9') f |= c == '-', c = getchar();
    while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
    s = f ? -s : s;
}

const int _ = 1e6 + 5, __ = 1e3 + 5;

int n, q, a[_], m, pos[_], f[__][__], g[_];

int main() {
#ifndef ONLINE_JUDGE
    file("cpp");
#endif
    read(n), read(q), m = sqrt(1.0 * n);
    for (rg int i = 1; i <= n; ++i) read(a[i]), pos[i] = (i - 1) / m + 1;
    for (rg int i = 1; i <= pos[n]; ++i) {
        memset(g, 0, sizeof g);
        for (rg int j = (i - 1) * m + 1; j <= i * m && j <= n; ++j) g[a[j]] = a[j];
        for (rg int j = 1; j <= 1000; ++j) if (!g[j]) g[j] = g[j - 1];
        for (rg int j = 1; j <= 1000; ++j) {
            for (rg int k = j; k <= 1000; k += j)
                f[i][j] = max(f[i][j], g[k - 1] - (k - j));
            f[i][j] = max(f[i][j], g[1000] % j);
            //这句话我也不知道为什么要加但是确实是加了就过了不加就WA
        }
    }
    for (rg int l, r, p, ans; q--; ) {
        read(l), ++l, read(r), ++r, read(p), ans = 0;
        if (l > r) swap(l, r);
        if (pos[l] == pos[r])
            for (rg int i = l; i <= r; ++i) ans = max(ans, a[i] % p);
        else {
            for (rg int i = pos[l] + 1; i <= pos[r] - 1; ++i) ans = max(ans, f[i][p]);
            for (rg int i = l; i <= pos[l] * m; ++i) ans = max(ans, a[i] % p);
            for (rg int i = (pos[r] - 1) * m + 1; i <= r; ++i) ans = max(ans, a[i] % p);
        }
        printf("%d\n", ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/zsbzsb/p/12283829.html

时间: 2024-08-30 08:22:53

「JSOI2013」贪心的导游的相关文章

LibreOJ #515. 「LibreOJ β Round #2」贪心只能过样例

二次联通门 : LibreOJ #515. 「LibreOJ β Round #2」贪心只能过样例 /* LibreOJ #515. 「LibreOJ β Round #2」贪心只能过样例 很显然 贪心方程哦不 dp方程为 f[i][j]=f[i-1][j-k*k] 但是这样的话复杂度就是O(N ^ 5) 那么就用bitset优化一下 就ok了 */ #include <iostream> #include <cstdio> #include <bitset> void

「CSPS 2019 十一」 贪心

一般来说,如果题目需要求一个最优解或者最小(大)花费之类的,而且除了暴力之外想不到什么好方法,那么就可能需要用贪心. 通常地,我们猜想一些步骤能不能直接使用贪心,然后再去证明这个贪心是对的. 有时候可能要多想几种贪心才能找到正确的那一种. New Year Snowmen Description 要堆起一个雪人,需要三个不同大小的雪球.现在有 \(n\) 个给定大小的雪球,问最多能堆起多少个雪人,并输出方案. Solution 每次用数量最多的三个雪球是最优的.可以用一个单调队列,每次取出最大的

「BZOJ4029」[HEOI2015] 定价 贪心

「BZOJ4029」[HEOI2015] 定价 2015年4月28日2,7490 Description 在市场上有很多商品的定价类似于 999 元.4999 元.8999 元这样.它们和 1000 元.5000 元和 9000 元并没有什么本质区别,但是在心理学上会让人感觉便宜很多,因此也是商家常用的价格策略.不过在你看来,这种价格十分荒谬.于是你如此计算一个价格 p(p 为正整数)的荒谬程度: 1.首先将 p 看做一个由数字组成的字符串(不带前导 0): 2.然后,如果 p 的最后一个字符是

LibreOJ #2012. 「SCOI2016」背单词

二次联通门 : LibreOJ #2012. 「SCOI2016」背单词 /* LibreOJ #2012. 「SCOI2016」背单词 Trie + 贪心 大家都吐槽题目反人类 可我觉得还好,毕竟见的多了 不会做啊.. 正解好巧妙 考虑一下,发现一操作完全不必要,可以省去 因为所有的字符串的后缀关系会形成一个树 那么把字符串倒序插入Trie中 建树,每次向子树小的一个点转移即可 */ #include <cstdio> #include <algorithm> #include

LibreOJ #2016. 「SCOI2016」美味

二次联通门 : LibreOJ #2016. 「SCOI2016」美味 /* LibreOJ #2016. 「SCOI2016」美味 dalao们都在说这题如果没有加法balabala就可以用可持久化trie解决了 然而我连那个也不会啊QAQ 此题用主席树 从高位到低位贪心 能填1就填1,也就是查询一段区间有没有某个范围的数 (然而由乃dalao说可持久化线段树和可持久化trie是一个东西) */ #include <cstdio> #include <iostream> #inc

「ZJOI2018」历史

「ZJOI2018」历史 前置知识 \(\text{LCT}\) 维护子树信息,考虑辅助树上一个节点的子树信息只是其代表的这一段链的信息,设 \(S(u)\) 为节点 \(u\) 的子树信息,那么在辅助树上我们维护的是: \[ S(u)=S(lson)+S(rson)+val(u) \] 考虑它们的实际意义 \(lson\) 是 \(u\) 的父亲,\(rson\) 是 \(u\) 的重儿子,显然 \(S(lson)\) 是我们不需要的,而真正的辅助信息只算了节点本身和重儿子. 考虑按照这样算的

「CF858F」 Wizard&#39;s Tour

传送门 Luogu 解题思路 首先对于树的情况,我们很显然有一种贪心策略: 对于每一个节点先匹配子树,然后在还可以匹配的儿子间尽可能匹配,要是多出来一个就往上匹配. 推广到图的情况... 我们在图的生成树上 \(\text{DFS}\) ,即时删边,防止重复访问. 然后记录一个 \(f[x]\),表示直接与 \(x\) 节点并且还可以用来匹配的点. 那么我们直接一边 \(\text{DFS}\) ,一边匹配就好了. 最后输出答案即可. 细节注意事项 没什么细节,就是要仔细想一想 参考代码 #in

「网络流」

$Tasklist$ 无限之环 星际竞速 4823: 老C的方块 2007: 海拔 还有51nod上的 集合交易 「奇怪的游戏」:小学数学+最大流 如果不相等,算出来要多叠多少层,否则答案具有二分性.check用最大流 土兵占领:补集转化+最小割 转化为最多有多少士兵能同时给一行和一列作出贡献,然后最小割可以做 「紧急疏散」:增量+最大流 必须根据时间拆点,而不能每经过一个时间给终点流量+1,因为不能让后面的人占用前面的流量 狼抓兔子:最小割/对偶图 不管写最小割还是对偶图都是模板 「切糕」:最

「CH6101」最优贸易

「CH6101」最优贸易 传送门 考虑一种贪心的思想:我们要尽量买价格小的货物,并尽量高价转卖. 我们记 : \(mn[i]\) 为从点 \(1\) 走到点 \(i\) 经过的价格最小的货物的价格. \(mx[i]\) 为从点 \(i\) 走到点 \(n\) 经过的价格最大的货物的价格. 这两个东西可以跑两次 \(\text{SPFA}\) 求得. 那么对于任何一个点,如果它位于最优解对应的路径上,那么该最优值一定不会小于 \(mx[i] - mn[i]\) 那么我们就可以把每个点 \(i\)