传送门

yysy,我考场上连\(n^2\)的暴力都没搞出来

这里实际上求的是最小权极大上升子序列

但这个跟题目几乎没什么直接联系,貌似只是因为极大上升子序列一定是符合题意的一组解

然后题里要求总权值最小,所以是最小权极大上升子序列

\(n^2\)代码:

int minn, mindp;
for (int i=1; i<=n; ++i) {
minn=INF, mindp=INF;
for (int j=i-1; j; --j) if (p[j]<p[i]) {if (p[i]-p[j]<minn) minn=p[i]-p[j], mindp=min(mindp, dp[j]);}
dp[i]+=mindp==INF?0:mindp;
for (int j=i-1; j; --j) if (p[j]<p[i]) vis[j]=1;
dp[i]+=c[i];
}
for (int i=1; i<=n; ++i) if (!vis[i]) ans=min(ans, dp[i]);
printf("%d\n", ans);

然后正解:

考虑如何求出所有极大上升子序列中的最小总权值

首先发现对于一个位置i,它左侧所有可能作为可以转移的子序列有端点的点j可以用一个单调栈维护

但由于有个\(p[i]\)的限制,这个单调栈貌似在一个位置弹过元素后就失效了

其实这里可以用线段树去维护它

这个\(p[i]\)的限制可以用一个「翻转坐标系」的技巧处理掉

  • 当出现形如「\(p[i]<p[j]\)的前提下,对符合要求的\(i\),\(j\)进行操作」的限制条件时,可以通过将\(p[\ ]\)翻转为\(x\)轴,\(i\)翻转为\(y\)轴的方式

    通过翻转坐标系将这样的限制条件转化为一个序列上的区间操作

  • 「线段树维护单调栈」:给出一个序列,这个序列的每个位置有两个值 \(a_i,f_i\),每次询问一个区间,把这个区间的所有数以\(a\)为关键字,从左到右做一个单调递减的栈,求这个单调栈中的元素的\(f\)值的最小值。

具体实现为对于每个区间,额外维护\(rmx[\ ],f_{min}[\ ],val[\ ]\)三个数组

\(rmx[\ ]\)记录当前区间的右子区间中的最大值,实际上就是左子区间中小于\(rmx[p]\)的数应该被弹掉

\(f_min[\ ]\)记录query(p<<1, l, mid, rmx[p]),这个东西在pushup时就可以维护出来,其意义在于确保query是\(O(nlog^2n)\)的

\(val[\ ]\)就是记录\(f_i\)用的,但在这里非常容易搞混

核心在于这个写的有点麻烦的query函数

int query(int p, int l, int r, int q) {
if (l<=tl(p)&&r>=tr(p)) {
if (!maxn(p)) return INF;
if (tl(p)==tr(p)) return maxn(p)>q?dp(maxn(p)):INF;
if (q>rmx(p)) return query(p<<1, l, r, q);
else return min(fmn(p), query(p<<1|1, l, r, q));
}
int mid=(tl(p)+tr(p))>>1, ans=INF;
if (r>mid) {
int rmax=qmax(p<<1|1, mid+1, r);
if (q>rmax) {
if (l<=mid) return query(p<<1, l, r, q);
else return INF;
}
else {
if (l<=mid) return min(query(p<<1, l, r, rmax), query(p<<1|1, l, r, q));
else return query(p<<1|1, l, r, q);
}
}
else return query(p<<1, l, r, q);
}

总时间复杂度\(O(nlog^2n)\)

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 200010
#define ll long long
#define ld long double
#define usd unsigned
#define ull unsigned long long
//#define int long long #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
char buf[1<<21], *p1=buf, *p2=buf;
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
} int n;
int p[N], c[N]; namespace force{
int head[N], size, ans=INF;
bool vis[N];
struct edge{int to, next;}e[N*100];
inline void add(int s, int t) {edge* k=&e[++size]; k->to=t; k->next=head[s]; head[s]=size;}
void dfs(int sum) {
//cout<<"dfs "<<sum<<endl;
bool cge[30], all=1;
memset(cge, 0, sizeof(bool)*(n+5));
for (int i=1; i<=n; ++i) {
if (!vis[i]) {
vis[i]=1;
for (int j=head[i],v; j; j=e[j].next) {
v = e[j].to;
if (!vis[v]) {
cge[v]=1;
vis[v]=1;
}
}
dfs(sum+c[i]);
vis[i]=0;
for (int j=head[i],v; j; j=e[j].next) {
v = e[j].to;
if (cge[v]) vis[v]=0;
}
all=0;
}
}
if (all) ans=min(ans, sum);
}
void solve() {
for (int i=1; i<=n; ++i) {
for (int j=i-1; j; --j) if (p[j]>p[i]) add(i, j); //, cout<<"add "<<i<<' '<<j<<endl;
for (int j=i+1; j<=n; ++j) if (p[j]<p[i]) add(i, j); //, cout<<"add "<<i<<' '<<j<<endl;
}
dfs(0);
printf("%d\n", ans);
exit(0);
}
} namespace task1{
int r[N];
int head[N], size, ans=INF;
bool vis[N];
struct edge{int to, next;}e[N*100];
inline void add(int s, int t) {edge* k=&e[++size]; k->to=t; k->next=head[s]; head[s]=size;}
void solve() {
for (int i=1; i<=n; ++i) r[i]=i;
for (int i=1; i<=n; ++i) {
for (int j=i-1; j; --j) if (p[j]>p[i]) add(i, j); //, cout<<"add "<<i<<' '<<j<<endl;
for (int j=i+1; j<=n; ++j) if (p[j]<p[i]) add(i, j); //, cout<<"add "<<i<<' '<<j<<endl;
}
int sum, cnt, cnt2=0;
while (++cnt2%5 || clock()<=600000) {
sum=0; cnt=0;
random_shuffle(r+1, r+n+1);
memset(vis, 0, sizeof(bool)*(n+5));
for (int i=1; i<=n; ++i) {
if (vis[r[i]]) continue;
sum+=c[r[i]]; ++cnt; vis[r[i]]=1;
for (int j=head[r[i]],v; j; j=e[j].next) {
v = e[j].to;
if (!vis[j]) {vis[j]=1; ++cnt;}
}
if (sum>ans) goto jump;
if (cnt==n) {ans=min(ans, sum); goto jump;}
}
jump: ;
}
printf("%d\n", ans);
//cout<<cnt2<<endl;
exit(0);
}
} namespace task2{
int dp[N], ans=INF;
bool vis[N];
void solve() {
int minn, mini=0, mindp;
for (int i=1; i<=n; ++i) {
cout<<"i: "<<i<<" p[i]: "<<p[i]<<endl;
minn=INF, mindp=INF;
for (int j=i-1; j; --j) if (p[j]<p[i]) {/*cout<<"1: "<<p[j]<<endl;*/ if (p[i]-p[j]<minn) minn=p[i]-p[j], mini=j, mindp=min(mindp, dp[j]), cout<<"2: "<<p[j]<<endl;}
dp[i]+=mindp==INF?0:mindp;
for (int j=i-1; j; --j) if (p[j]<p[i]) vis[j]=1;
dp[i]+=c[i];
}
//for (int i=1; i<=n; ++i) cout<<vis[i]<<' '; cout<<endl;
//for (int i=1; i<=n; ++i) cout<<dp[i]<<' '; cout<<endl;
for (int i=1; i<=n; ++i) if (!vis[i]) ans=min(ans, dp[i]);
printf("%d\n", ans);
exit(0);
}
} namespace task{
const int SIZE=N<<2;
int tl[SIZE], tr[SIZE], maxn[SIZE], rmx[SIZE], fmn[SIZE], dp[SIZE];
#define tl(p) tl[p]
#define tr(p) tr[p]
#define maxn(p) maxn[p]
#define dp(p) dp[p]
#define rmx(p) rmx[p]
#define fmn(p) fmn[p]
int qmax(int p, int l, int r) {
if (l<=tl(p)&&r>=tr(p)) return maxn(p);
int mid=(tl(p)+tr(p))>>1, ans=0;
if (l<=mid) ans=max(ans, qmax(p<<1, l, r));
if (r>mid) ans=max(ans, qmax(p<<1|1, l, r));
return ans;
}
int query(int p, int l, int r, int q) {
//cout<<"query "<<p<<' '<<l<<' '<<r<<' '<<q<<endl;
if (l<=tl(p)&&r>=tr(p)) {
if (!maxn(p)) return INF;
//cout<<"pos1"<<endl;
if (tl(p)==tr(p)) return maxn(p)>q?dp(maxn(p)):INF;
//cout<<"pos2"<<endl;
if (q>rmx(p)) return query(p<<1, l, r, q);
else return min(fmn(p), query(p<<1|1, l, r, q));
}
int mid=(tl(p)+tr(p))>>1, ans=INF;
if (r>mid) {
int rmax=qmax(p<<1|1, mid+1, r);
if (q>rmax) {
if (l<=mid) return query(p<<1, l, r, q);
else return INF;
}
else {
if (l<=mid) return min(query(p<<1, l, r, rmax), query(p<<1|1, l, r, q));
else return query(p<<1|1, l, r, q);
}
}
else return query(p<<1, l, r, q);
}
void pushup(int p) {
maxn(p)=max(maxn(p<<1), maxn(p<<1|1));
rmx(p)=maxn(p<<1|1);
fmn(p)=query(p<<1, tl(p<<1), tr(p<<1), rmx(p));
//cout<<p<<": "<<maxn(p)<<' '<<rmx(p)<<' '<<fmn(p)<<endl;
}
void build(int p, int l, int r) {
tl(p)=l; tr(p)=r; fmn(p)=INF;
if (l>=r) return ;
int mid=(l+r)>>1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
}
void upd(int p, int pos, int val) {
//cout<<"upd "<<p<<' '<<tl(p)<<' '<<tr(p)<<' '<<pos<<' '<<val<<endl;
if (tl(p)==tr(p)) {maxn(p)=rmx(p)=fmn(p)=val; return ;}
int mid=(tl(p)+tr(p))>>1;
if (pos<=mid) upd(p<<1, pos, val);
else upd(p<<1|1, pos, val);
pushup(p);
}
void solve() {
build(1, 1, n);
for (int i=1,t; i<=n; ++i) {
//cout<<i<<": "<<query(1, 1, p[i], 0)<<endl;
t=query(1, 1, p[i], 0);
//cout<<endl;
dp[i]=(t==INF?0:t)+c[i];
upd(1, p[i], i);
}
printf("%d\n", query(1, 1, n, 0));
exit(0);
}
} signed main()
{
#ifdef DEBUG
freopen("1.in", "r", stdin);
#endif n=read();
for (int i=1; i<=n; ++i) p[i]=read();
for (int i=1; i<=n; ++i) c[i]=read();
//if (n<=15) force::solve();
//else task1::solve();
//task2::solve();
task::solve(); return 0;
}

题解 God Knows的更多相关文章

  1. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  2. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  3. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  4. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

  5. 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解

    题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...

  6. 2016ACM青岛区域赛题解

    A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

  7. poj1399 hoj1037 Direct Visibility 题解 (宽搜)

    http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...

  8. 网络流n题 题解

    学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...

  9. CF100965C题解..

    求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...

  10. JSOI2016R3 瞎BB题解

    题意请看absi大爷的blog http://absi2011.is-programmer.com/posts/200920.html http://absi2011.is-programmer.co ...

随机推荐

  1. ScienceDirect内容爬虫

    爬虫违法,本贴方法只限于个人对数据的分析使用,其爬虫程序已作相关设置,以减小服务器压力.不适宜长期使用. 一.前期准备 1.使用chrome打开ScienceDirect网站(https://www. ...

  2. Java基础00-第一个程序2

    1. 常用DOS命令 1.1 打开命令提示窗口 按下win+R 输入cmd 按下回车键 得到命令提示窗口 1.2 常用命令 2. Path环境变量的配置 2.1 为什么要配置Path环境变量 2.2 ...

  3. js学习-es6实现枚举

    最近大部分时间再写dart,突然用到js,发现js不能直接声明一个枚举.搜索发现还是有实现的方式,于是总结一下. 目录 枚举特点 Object.freeze() Symbol 实现 体现不可更改 体现 ...

  4. MySQL全面瓦解26:代码评审中的MySQL(团队使用)

    数据库对象命名规范 数据库对象 数据库对象是数据库的组成部分,常见的有以下几种: 表(Table ).索引(Index).视图(View).图表(Diagram).缺省值(Default).规则(Ru ...

  5. C++11 左值引用和右值引用与引用折叠和完美转发

    1.左值与右值 最感性的认识. 当然,左值也是可以在右边的. 左值是可以被修改的,右值不能. 当然取地址也是. 生存周期一般左值会比右值的长,一般右值都计算时产生的无名临时对象,存在时间比较短. 下面 ...

  6. react-router 基本使用

    # 1. 理解react-router react的一个插件库 专门用来实现一个SPA应用 基于react的项目基本都会用到此库 # 2. 几个重要问题## 1). SPA应用 单页Web应用(sin ...

  7. Linux安装Tomcat-Nginx-FastDFS-Redis-Solr-集群——【第九集-补充-热部署项目到tomcat中,但是数据库配置文件错误,中途停止部署,导致执行shutdow.sh报错异常: Could not contact localhost:8005. Tomcat may not be running error while shutting down】

    1,经过千辛万苦的尝试和百度,终于一个博客:http://stackmirror.caup.cn/page/skxugjqj0ldc关于catalina.sh文件的执行引起了我的注意: 2,我执行ca ...

  8. 搭建kerberos和NTP服务器以及安全的NFS服务

    说明:这里是Linux服务综合搭建文章的一部分,本文可以作为单独搭建Kerberos和NTP时钟服务的参考. 注意:这里所有的标题都是根据主要的文章(Linux基础服务搭建综合)的顺序来做的. 如果需 ...

  9. dubbo(四)

    前言 1.浅谈架构的发展 首先,要了解dubbo,就得了解,它是在什么背景下产生的?这就需要从架构的发展说起. 孟老师从事软件开发2008年份,那时候我上高一,那个时候,淘宝.京东都还没有火起来.那个 ...

  10. 记一次系统崩溃事件【Mac版】

    事件:Mac系统崩溃,导致电脑数据丢失,以及数据安全备份措施的不到位的教训! 解决措施: 1.开机后按:Command+R 按开机键 ,进入Mac 实用工具, 选择磁盘工具.由于没有备份直接抹掉磁盘. ...