「JSOI2011」汇总

「JSOI2011」柠檬

斜率优化题。
在优化前,还有一个值得一提的优化:
对于最后的最有分割方案,每一段的两个端点一定是同颜色的,并且作为这一段的 \(s_0\)
证明:如果不作为这一段的 \(s_0\),那么它显然没有贡献,把这一个单独分出来显然更优,直到最后两个端点就一定都是 \(s_0\) ,颜色相同。
那么我们只需要从之前和该点种类相同的位置进行转移即可。
这样就从直接枚举的复杂度 \(O(n^3)\) 优化到了 \(O(n^2)\) ,但还是不够,继续考虑优化。
我们先把转移方程写出来:
\(dp_i\) 表示把前 \(i\) 个取完,且 \(i\) 点作为一段的终点最大收益。
\[dp_i=\max\limits_{1\le j \le i,a_j=a_i}\left\{dp_{j-1}+s_i(p_i-p_j+1)^2\right\}\]
\(p_i\) 表示第 \(i\) 个点是种类为 \(s_i\) 的第 \(p_i\) 个点。
根据斜率优化的一些做法,我们可以把式子化成这样:
\(p_i\times 2p_js_j+dp_i-s_i(p_i+1)^2=dp_{j-1}-2a_jp_j+a_jp_j^2\)
设 \(x_i = 2s_ip_i,y_i=dp_{i-1}-2s_ip_i+s_ip_i^2\)
\(p_ix_j+dp_i-s_i(p_i+1)^2=y_j\)
因为要让 \(dp_i\) 最大化,所以我们对每一种颜色都用单调栈维护一个上凸包,这样才能满足决策单调性。
注意一点细节:
因为我们的转移点 \(j\) 的范围是 \([1,i]\) 的,而我们再插入 \(j\) 这个点时只有 \(dp_{j-1}\) 这个信息,为了能取到 \(dp_{i-1}\) ,我们需要在寻找最优转移点之前就把 \(i\) 加入单调栈。
参考代码:

#include <cstdio>
#include <vector>
#define rg register
#define int long long
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
using namespace std;
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 _ = 1e5 + 5;

int n, s[_], p[_], pos[_], dp[_];
vector < int > stk[_];

inline int X(int i) { return 2 * s[i] * p[i]; }

inline int Y(int i) { return dp[i - 1] - 2 * s[i] * p[i] + s[i] * p[i] * p[i]; }

inline double slope(int i, int j) { return (double) (Y(i) - Y(j)) / (X(i) - X(j)); }

signed main() {
#ifndef ONLINE_JUDGE
    file("cpp");
#endif
    read(n);
    for (rg int i = 1; i <= n; ++i) read(s[i]), p[i] = ++pos[s[i]];
#define A stk[c][stk[c].size() - 2]
#define B stk[c][stk[c].size() - 1]
    for (rg int i = 1; i <= n; ++i) {
        int c = s[i];
        while (stk[c].size() > 1 && slope(A, B) < slope(A, i)) stk[c].pop_back();
        stk[c].push_back(i);
        while (stk[c].size() > 1 && slope(A, B) < p[i]) stk[c].pop_back();
        int j = stk[c].back();
        dp[i] = dp[j - 1] + s[i] * (p[i] - p[j] + 1) * (p[i] - p[j] + 1);
    }
#undef A
#undef B
    printf("%lld\n", dp[n]);
    return 0;
}

「JSOI2011」分特产

传送门
计数题。
考虑容斥掉每人至少一个的限制。
就直接枚举至少有多少人没有分到特产,然后剩下的随便分。
\[Ans = \sum_{i = 0}^n (-1)^i {n \choose i} \prod_{j = 1}^m {n - i + a_j - 1 \choose n - i - 1}\]
参考代码:

#include <cstdio>
#define rg register
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
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 _ = 5010, p = 1e9 + 7;

int n, m, a[_], fac[_], ifc[_];

inline int C(int N, int M) { return 1ll * fac[N] * ifc[M] % p * ifc[N - M] % p; }

inline void init(int N) {
    fac[0] = ifc[0] = ifc[1] = 1;
    for (rg int i = 1; i <= N; ++i) fac[i] = 1ll * fac[i - 1] * i % p;
    for (rg int i = 2; i <= N; ++i) ifc[i] = 1ll * (p - p / i) * ifc[p % i] % p;
    for (rg int i = 1; i <= N; ++i) ifc[i] = 1ll * ifc[i - 1] * ifc[i] % p;
}

int main() {
#ifndef ONLINE_JUDGE
    file("cpp");
#endif
    read(n), read(m), init(_ - 1);
    for (rg int i = 1; i <= m; ++i) read(a[i]);
    int ans = 0;
    for (rg int i = 0; i <= n; ++i) {
        int tmp = 1;
        for (rg int j = 1; j <= m; ++j) tmp = 1ll * tmp * C(n - i - 1 + a[j], n - i - 1) % p;
        ans = (ans + 1ll * (i & 1 ? -1 : 1) * C(n, i) * tmp % p + p) % p;
    }
    printf("%d\n", ans);
    return 0;
}

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

时间: 2024-08-30 13:41:56

「JSOI2011」汇总的相关文章

「JSOI2011」任务调度

「JSOI2011」任务调度 传送门 一开始还在想写平衡树,看到 \(\text{TRANS}\) 操作后就晓得要用可并堆了. 这题好像就是个可并堆的板子题??? ADD 直接往对应的对里面加元素 DEC 在对应的堆里面找到这个元素,讨论一下它是不是根节点,然后抠出来重新加进去 TRANS 合并两个堆 MIN 查堆顶的值 WORK 讨论一下根节点和它儿子的大小关系来判 ERROR 的情况,然后就和 DEC 一样了 参考代码: #include <algorithm> #include <

「JSOI2010」汇总

「JSOI2010」旅行 传送门 比较妙的一道 \(\text{DP}\) 题,思维瓶颈应该就是如何确定状态. 首先将边按边权排序. 如果我们用 \(01\) 串来表示 \(m\) 条边是否在路径上,那么我们就可以通过钦定前 \(x\) 条边在路径上来确定目标状态. 其中有的边消耗了魔法使用次数,有的没消耗. 那么我们就可以设 \(dp[i][j][k]\) 表示到点 \(i\) ,经过了前 \(j\) 条被钦定边,并且使用了 \(k\) 次魔法的最短路,那么转移就是(假设我们现在要从点 \(u

「JSOI2011」柠檬

传送门 Luogu 解题思路 还是一道斜率优化题. 在优化前,还有一个值得一提的优化: 对于最后的最有分割方案,每一段的两个端点一定是同颜色的,并且作为这一段的 \(s_0\) 证明:如果不作为这一段的 \(s_0\),那么它显然没有贡献,把这一个单独分出来显然更优,直到最后两个端点就一定都是 \(s_0\) ,颜色相同. 那么我们只需要从之前和该点种类相同的位置进行转移即可. 这样就从直接枚举的复杂度 \(O(n^3)\) 优化到了 \(O(n^2)\) ,但还是不够,继续考虑优化. 我们先把

大数据和「数据挖掘」是何关系?---来自知乎

知乎用户,互联网 244 人赞同 在我读数据挖掘方向研究生的时候:如果要描述数据量非常大,我们用Massive Data(海量数据)如果要描述数据非常多样,我们用Heterogeneous Data(异构数据)如果要描述数据既多样,又量大,我们用Massive Heterogeneous Data(海量异构数据)--如果要申请基金忽悠一笔钱,我们用Big Data(大数据) 编辑于 2014-02-2817 条评论感谢 收藏没有帮助举报作者保留权利 刘知远,NLPer 4 人赞同 我觉得 大数据

AC日记——「HNOI2017」单旋 LiBreOJ 2018

#2018. 「HNOI2017」单旋 思路: set+线段树: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 #define maxtree maxn<<2 int val[maxtree],tag[maxtree],L[maxtree],R[maxtree],mid[maxtree]; int op[maxn],ki[maxn],bi[maxn],cnt,size,n,ch[maxn]

「随笔」基于当下的思考

马德,说好的技术blog,变成日记本了... 下午的时候莫名其妙的感到很颓废,因为自己的不够强大感到忧虑和危机感十足.现在每每行走在技术的道路上,常觉得如履薄冰,如芒在背. 上大学之前和现在的心态其实差别挺大的,视野的开阔远远不止局限于自己的脚下.不过,这里的「上大学之前」只是一个时间描述词,并不觉得大学是最适合学习的地方,我很失望. 世界上的人无论性别,区域,宗教,兴趣爱好,总可以在互联网上找到志趣相同的人,总是可以不断打破自己的常识与惯性思维.总是有在相同领域比自己更强的人,挺好的. 关于知

「Unity」与iOS、Android平台的整合:3、导出的Android-Studio工程

本文属于「Unity与iOS.Android平台的整合」系列文章之一,转载请注明出处. Unity默认导出的是Android-Eclipse工程,毕竟Eclipse for Android开发在近一两年才开始没落,用户量还是非常巨大的. 个人认为AndroidStudio非常好用,能轻易解决很多Eclipse解决不了或者很难解决的问题. 所以我将Unity导出的Andoid工程分为Eclipse和AndroidStudio两部分. 不过我之后的相关内容都会使用AndroidStudio,希望依然

开放的智力8:实用「成功学」

可实现的「成功学」 现在我想为这里的年轻人介绍一种可实现的「成功学」.希望这个我自创的理论,可以改变很多人的一生. 当我们评价一个事情值不值得去做.应该花多少精力去做的时候,应该抛弃单一的视角,而是分两个不同的维度来看,一是该事件将给我带来的收益大小(认知.情感.物质.身体方面的收益皆可计入),即「收益值」:二是该收益随时间衰减的速度,我称为「收益半衰期」,半衰期长的事件,对我们的影响会持续得较久较长. 这两个维度正交以后就形成了一个四象限图.我们生活.学习和工作中的所有事情都可以放进这个图里面

Linux 小知识翻译 - 「syslog」

这次聊聊「syslog」. 上次聊了「日志」(lgo).这次说起syslog,一看到log(日志)就明白是怎么回事了.syslog是获取系统日志的工具. 很多UINIX系的OS都采用了这个程序,它承担了「获取系统全部的日志」这个维持系统正常运行的重要任务. syslog的本体是「syslogd」这个daemon(一般翻译成守护进程),常驻内存中获取日志. syslog的特点是可以通过配置文件「/etc/syslog.conf」,对「哪种应用程序?哪种重要度的信息?记录在哪个文件中?」等进行细致的