简要题解

这套题比较 \(H_2O\)

建议题目背景美文共赏

\(\text{T1}\)

显然一个 \(O(n^3)\) 不能过的 \(dp\)

然而过了?!

用心在该卡时间的地方卡一卡

\(\text{Code}\)

#include <cstdio>
#include <algorithm>
#define re register
using namespace std;
typedef long long LL; const int N = 5005;
int n, m, C, lim[N], cnt, col[N];
LL f[N][N], g[N];
struct node{int v, w, c;}a[N];
inline bool cmp(node a, node b){return a.c < b.c;}
inline bool cmp1(node a, node b){return a.v > b.v;} inline void solve()
{
sort(a + 1, a + n + 1, cmp1);
LL ans = 0;
for(re int i = 1; i <= n; i++)
{
if (!m) break;
if (lim[a[i].c]) ans += a[i].v, --lim[a[i].c], --m;
}
printf("%lld\n", ans);
} int main()
{
freopen("diversity.in", "r", stdin), freopen("diversity.out", "w", stdout);
scanf("%d%d%d", &n, &m, &C);
int bz1 = 1, bz2 = 1;
for(re int i = 1; i <= n; i++) scanf("%d%d%d", &a[i].v, &a[i].w, &a[i].c), bz2 = (bz2 && (a[i].w == 1));
sort(a + 1, a + n + 1, cmp);
for(re int i = 1; i <= C; i++) scanf("%d", &lim[i]), bz1 = (bz1 && lim[i] >= m), lim[i] = (lim[i] > m ? m : lim[i]);
if (bz2){solve(); return 0;}
int r;
for(re int l = 1; l <= n; l = r + 1)
{
r = l, col[++cnt] = a[l].c;
while (r < n && a[r + 1].c == a[l].c) ++r;
if (bz1) r = n;
for(re int i = 1; i <= r - l + 1; i++)
for(re int j = lim[a[l].c]; j >= a[i + l - 1].w; j--)
f[cnt][j] = max(f[cnt][j], f[cnt][j - a[i + l - 1].w] + a[i + l - 1].v);
}
if (bz1){printf("%lld\n", f[1][m]); return 0;}
for(re int i = 1; i <= cnt; i++)
for(re int j = m; j >= 0; j--)
for(re int k = 0; k <= min(j, lim[col[i]]); k++)
g[j] = max(g[j], g[j - k] + f[i][k]);
printf("%lld\n", g[m]);
}

\(\text{T2}\)

二分答案,考虑如何 \(check\)

贪心的想,将 \(a\) 排序,一一对应要弄出的自然数序列 \(b\)

然后就是快速计算代价

考虑一个位置,前面的代价是 \(b_i - a_i\) 的形式,后面的是 \(a_i - b_i\) 的形式(连续性很明显)

二分这个位置的话是 \(O(nlog^2n)\) 的,常数优秀就可以过

实际上这个分割的位置有单调性,指针处理即可

\(\text{Code}\)

#include <cstdio>
#include <iostream>
#include <algorithm>
#define re register
using namespace std;
typedef long long LL; const int N = 1e6 + 5;
int n;
LL num, a[N], sum[N]; inline void read(int &x)
{
x = 0; char ch = getchar(); int f = 1;
for(; !isdigit(ch); f = (ch == '-' ? -1 : f), ch = getchar());
for(; isdigit(ch); x = (x<<3) + (x<<1) + (ch^48), ch = getchar());
x *= f;
}
inline LL cost(int l, int r)
{
if (l > r) return 0;
return 1LL * (r + l) * (r - l + 1) / 2;
}
inline int check(int mid)
{
LL res = num + 1; int r = mid + 1;
for(re int i = 1; i <= n - mid; i++)
{
while (r && r - 1 < a[i + r - 1]) --r;
res = min(res, cost(1, r - 1) - (sum[i + r - 1] - sum[i - 1]) + (sum[i + mid] - sum[i + r - 1]) - cost(r, mid));
}
return res <= num;
} int main()
{
freopen("dream.in", "r", stdin), freopen("dream.out", "w", stdout);
read(n), scanf("%lld", &num);
for(re int i = 1, x; i <= n; i++) read(x), a[i] = x;
sort(a + 1, a + n + 1);
for(re int i = 1; i <= n; i++) sum[i] = sum[i - 1] + a[i];
int l = 0, r = n - 1, mid, res = -1;
while (l <= r)
{
mid = l + r >> 1;
if (check(mid)) res = mid, l = mid + 1;
else r = mid - 1;
}
printf("%lld", res + 1);
}

\(\text{T3}\)

题目理解后就很好做了

考虑答案的暴力形式,莫反一下

\[ans = \frac{\sum_{d=1}^k d \sum_{t=1}^{\lfloor \frac{k}{d} \rfloor} \mu(t) \lfloor \frac{k}{dt} \rfloor ^n}{k^n}
\]

发现是个数论分块套数论分块的形式

\(\text{Code}\)

#include <cstdio>
#define re register
#define LL long long
using namespace std; const int N = 1e6, P = 998244353, inv2 = 499122177;
int totp, n, k, T, pr[N], vis[N + 5], mu[N + 5], pw[N + 5]; inline int fpow(LL x, LL y)
{
if (x < k && pw[x]) return pw[x];
LL res = 1, xx = x;
for(; y; y >>= 1, x = x * x % P) if (y & 1) res = res * x % P;
if (xx < k) pw[xx] = res;
return res;
} inline void Euler()
{
vis[1] = mu[1] = 1;
for(re int i = 2; i <= N; i++)
{
if (!vis[i]) pr[++totp] = i, mu[i] = -1;
for(re int j = 1; j <= totp && i * pr[j] <= N; j++)
{
vis[i * pr[j]] = 1;
if (!(i % pr[j])) break;
mu[i * pr[j]] = -mu[i];
}
}
for(re int i = 1; i <= N; i++) mu[i] += mu[i - 1];
} inline LL F(int up)
{
int r; LL sum = 0;
for(re int l = 1; l <= up; l = r + 1)
{
r = up / (up / l);
sum = (sum + 1LL * (mu[r] - mu[l - 1] + P) % P * fpow(up / l, n) % P) % P;
}
return sum;
} int main()
{
freopen("dance.in", "r", stdin), freopen("dance.out", "w", stdout);
Euler(), scanf("%d", &T);
for(; T; --T)
{
scanf("%d%d", &n, &k);
for(re int i = 0; i <= k; i++) pw[i] = 0;
LL ans = 0; int r;
for(re int l = 1; l <= k; l = r + 1)
{
r = k / (k / l);
ans = (ans + 1LL * (r + l) * (r - l + 1) % P * inv2 % P * F(k / l) % P) % P;
}
printf("%lld\n", ans * fpow(fpow(k, n), P - 2) % P);
}
}

\(\text{T4}\)

考虑一个坐标向下走的贡献

把一个坐标能左右延伸出的位置处理出来,可单调栈做到 \(O(n)\) 也可懒惰的 \(O(n log n)\) 二分 + \(ST\) 表

然后把坐标按 \(y\) 从小到大排序,扫过的点就满足了 \(y\) 的限制

先处理当前点可延伸区间的贡献再在树状数组上加入这个点

非常之简单

\(\text{Code}\)

#include <iostream>
#include <cstdio>
#include <algorithm>
#define re register
using namespace std;
typedef long long LL; const int N = 5e5 + 5, P = 998244353;
int n, m, mx[N][21], lg[N];
struct point{int x, y, w, l, r;}p[N];
inline bool cmpy(point a, point b){return a.y < b.y;} inline void read(int &x)
{
x = 0; char ch = getchar(); int f = 1;
for(; !isdigit(ch); f = (ch == '-' ? -1 : f), ch = getchar());
for(; isdigit(ch); x = (x<<3) + (x<<1) + (ch^48), ch = getchar());
x *= f;
} inline int query(int l, int r)
{
int k = lg[r - l + 1];
return max(mx[l][k], mx[r - (1 << k) + 1][k]);
}
inline void prepare()
{
for(re int j = 1; j <= lg[n]; j++)
for(re int i = 1; i + (1 << j) - 1 <= n; i++)
mx[i][j] = max(mx[i][j - 1], mx[i + (1 << j - 1)][j - 1]);
for(re int i = 1; i <= m; i++)
{
int l = 1, r = p[i].x, mid;
while (l <= r)
{
mid = l + r >> 1;
if (query(mid, p[i].x) < p[i].y) p[i].l = mid, r = mid - 1;
else l = mid + 1;
}
l = p[i].x, r = n;
while (l <= r)
{
mid = l + r >> 1;
if (query(p[i].x, mid) < p[i].y) p[i].r = mid, l = mid + 1;
else r = mid - 1;
}
}
} struct node{LL s0, s1, s2;};
inline node operator - (const node a, const node b)
{
return node{(a.s0 - b.s0 + P) % P, (a.s1 - b.s1 + P) % P, (a.s2 - b.s2 + P) % P};
}
struct BIT{
LL c0[N], c1[N], c2[N];
inline int lowbit(int x){return x & (-x);}
inline void add(int x, LL v)
{
for(; x <= n; x += lowbit(x))
++c0[x], c1[x] = (c1[x] + v) % P, c2[x] = (c2[x] + v * v % P) % P;
}
inline node getsum(int x)
{
int s0 = 0, s1 = 0, s2 = 0;
for(; x; x -= lowbit(x)) s0 = (s0 + c0[x]) % P, s1 = (s1 + c1[x]) % P, s2 = (s2 + c2[x]) % P;
return node{s0, s1, s2};
}
inline node query(int l, int r){return getsum(r) - getsum(l - 1);}
}T; int main()
{
freopen("flame.in", "r", stdin), freopen("flame.out", "w", stdout);
read(n), read(m), lg[0] = -1;
for(re int i = 1; i <= n; i++) read(mx[i][0]), lg[i] = lg[i >> 1] + 1;
for(re int i = 1; i <= m; i++) read(p[i].x), read(p[i].y), read(p[i].w);
prepare(), sort(p + 1, p + m + 1, cmpy); node t; LL ans = 0;
for(re int i = 1; i <= m; i++)
{
t = T.query(p[i].l, p[i].r), T.add(p[i].x, p[i].w);
ans = (ans + t.s0 * p[i].w % P * p[i].w % P - t.s1 * 2 * p[i].w % P + t.s2 + P) % P;
}
printf("%lld\n", ans);
}

JZOJ 【2021.11.10NOIP提高组联考】的更多相关文章

  1. JZOJ2020年8月11日提高组T4 景点中心

    JZOJ2020年8月11日提高组T4 景点中心 题目 Description 话说宁波市的中小学生在镇海中学参加计算机程序设计比赛,比赛之余,他们在镇海中学的各个景点参观.镇海中学共有n个景点,每个 ...

  2. JZOJ2020年8月11日提高组T3 页

    JZOJ2020年8月11日提高组T3 页 题目 Description 战神阿瑞斯听说2008年在中华大地上,将举行一届规模盛大的奥林匹克运动会,心中顿觉异常兴奋,他想让天马在广阔的天空上,举行一场 ...

  3. JZOJ2020年8月11日提高组T2 宝石

    JZOJ2020年8月11日提高组T2 宝石 题目 Description 见上帝动了恻隐之心,天后也想显示一下慈悲之怀,随即从口袋中取出一块魔术方巾,让身边的美神维纳斯拿到后堂的屏风上去试试,屏风是 ...

  4. JZOJ2020年8月11日提高组T1 密码

    JZOJ2020年8月11日提高组T1 密码 题目 Description 在浩浩茫茫的苍穹深处,住着上帝和他的神仆们,他们闲谈着下界的凡人俗事,对人世间表现的聪明智慧,大加赞赏.今天他们正在观赏大地 ...

  5. JZOJ2020年8月11日提高组反思

    JZOJ2020年8月11日提高组反思 T1 看到题 啊这?! 我看错了吗??? 我理解错题了吗?? 好吧没有-- 高精度模板题,不用多说 T2 看到这种矩阵的问题 以为是前缀和搞事情 结果呢 扫描线 ...

  6. 【2020.11.28提高组模拟】T1染色(color)

    [2020.11.28提高组模拟]T1染色(color) 题目 题目描述 给定 \(n\),你现在需要给整数 \(1\) 到 \(n\) 进行染色,使得对于所有的 \(1\leq i<j\leq ...

  7. JZOJ 5197. 【NOIP2017提高组模拟7.3】C

    5197. [NOIP2017提高组模拟7.3]C Time Limits: 1000 ms  Memory Limits: 262144 KB  Detailed Limits   Goto Pro ...

  8. JZOJ 5184. 【NOIP2017提高组模拟6.29】Gift

    5184. [NOIP2017提高组模拟6.29]Gift (Standard IO) Time Limits: 1000 ms  Memory Limits: 262144 KB  Detailed ...

  9. JZOJ 5185. 【NOIP2017提高组模拟6.30】tty's sequence

    5185. [NOIP2017提高组模拟6.30]tty's sequence (Standard IO) Time Limits: 1000 ms  Memory Limits: 262144 KB ...

  10. JZOJ 5196. 【NOIP2017提高组模拟7.3】B

    5196. [NOIP2017提高组模拟7.3]B Time Limits: 1000 ms  Memory Limits: 262144 KB  Detailed Limits   Goto Pro ...

随机推荐

  1. volatile关键字在并发中有哪些作用?

    作者:小牛呼噜噜 | https://xiaoniuhululu.com 计算机内功.JAVA源码.职业成长.项目实战.面试相关资料等更多精彩文章在公众号「小牛呼噜噜」 前言 读过笔者之前的一篇文章J ...

  2. EASE-Grid经纬度与行列号转换公式 以 25KM的HDF数据为例

    /// <summary> /// 把经纬度转换成行列号 /// </summary> /// <param name="pLng"></ ...

  3. day20 关联查询与多表联查 & 子查询与union联合查询 & 数据库定义语言DDL

    day20 关联查询 #左连接:表名 left join 表名 以左表为主表,只显示与左表能匹配的行 SELECT s.*,q.* FROM student AS s LEFT JOIN queue_ ...

  4. .net 温故知新:【10】.NET ORM框架EFCore使用入门之CodeFirs、DBFirst

    前言:本系列是我自己学习.net相关知识,以便跟上.net跨平台的步伐,目前工作原因基本在.net Framework4.7以下,所以才有了这一系列的学习总结,但是并不是从基本的C#语法和基础知识开始 ...

  5. 【每日一题】【递归实现、自下而上、优化】-2022年1月12日-NC68 跳台阶

    描述一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个 n 级的台阶总共有多少种跳法(先后次序不同算不同的结果). 数据范围:0 \leq n \leq 400≤n≤40要求:时间复杂度: ...

  6. 【笔面试真题】ThoughtWorks-笔试-2022年1月21日

    一.选择填空判断 2n-1 二.算法题 算法题1:配对括号 算法题2:计算有效票数? 算法题3:求字符串中指定单词的数量 package com.jhliu20.real; import java.u ...

  7. Gepetto:使用chatGPT来对函数功能进行分析并重命名变量的IDA插件

    最近OpenAI的chatGPT很火,chatGPT是一个大型的语言模型,能够生成人类语言的文本,主要用于对话式的问答和聊天,以及模拟人类的对话行为 有关chatGPT的介绍就不多赘述了,相关内容很多 ...

  8. 【转载】EXCEL VBA 20个有用的ExcelVBA代码

    1.显示多个隐藏的工作表 如果你的工作簿里面有多个隐藏的工作表,你需要花很多时间一个一个的显示隐藏的工作表. 下面的代码,可以让你一次显示所有的工作表 Sub UnhideAllWoksheets() ...

  9. Http请求接口

    方法一.使用springboot框间自带的Http的工具类RestTemplate. RestTemplate为springframework中自带的处理Http的工具类. 具体用法 请求的接口 @R ...

  10. Spring+Quartz+Dom4j实现一个小项目

    目录 1.项目背景 2.技术介绍 3.实现代码 4.程序演示 5.打成jar包 1.项目背景 最近在工作中碰到了一个问题,一个叫aura的系统每天都会接收到许多xml,其中有些xml会包含错误信息,这 ...