Codeforces 1097E. Egor and an RPG game
首先考虑怎么算 $f(n)$ (就是题目里面那个 $f(n)$)
发现可以构造一组序列大概长这样: ${1,3,2,6,5,4,10,9,8,7,15,14,13,12,11,...,n(n+1)/2,n(n+1)/2-1,n(n+1)/2-2...n(n+1)/2-(n-1),(n+1)(n+2)/2,(n+1)(n+2)/2-1.....}$
然后发现这样构造的话,如果序列长度为 $k(k+1)/2$ ,那么至少需要分 $k$ 个数列
考虑证明这个即为上限,那么就是证明如果序列长度小于 $k(k+1)/2$ ,那么最多需要 $k-1$ 的数列
证明可以这样考虑,首先求出最长单调上升序列($LIS$),如果 $LIS$ 长度大于等于 $k$ ,那么可以直接把 $LIS$ 取出
然后序列长度就从小于 $k(k+1)/2$ 变成小于 $k(k+1)/2-k=(k-1)k/2$ ,相当于更小的子问题
所以如果序列长度在 $[(k-1)k/2,k(k+1)/2)$ 内,那么只要看看 $LIS$ 是否大于等于 $k$ 然后递归处理即可
现在问题是如果 $LIS$ 长度小于 $k$ 怎么办,发现我们一定可以用 $LIS$ 长度个下降子序列覆盖整个序列
构造下降子序列的方法我不太会说,看下面的一段代码或许比较清楚:
struct dat {
int id,val;
dat (int _id=,int _val=) { id=_id,val=_val; }
inline bool operator < (const dat &tmp) const {
return val!=tmp.val ? val<tmp.val : id<tmp.id;
}
};
void solve2(int mx)//mx是LIS长度
{
set <dat> S;
for(int i=;i<=mx;i++) S.insert(dat(m+i,N));
for(int i=;i<V.size();i++)//V 是当前序列,用vector存的
{
auto p = S.lower_bound(dat(-,V[i]));
ans[(*p).id].push_back(V[i]);
S.insert(dat((*p).id,V[i])); S.erase(*p);
}
m+=mx; V.clear();
}
考虑证明上面做法的正确性,容易想到反证法:
首先把当前的所有下降序列按此时末尾的数从小到大排序,那么对于第 $i$ 个下降序列末尾的数,它在原序列的位置一定比左边所有序列末尾的数都大
因为如果不是这样的话左边的数完全可以接到这个数的后面(仔细想想)
那么由于这个东西对于每个当前每个下降序列都成立,那么可以发现当前所有下降序列的末尾如果取出来刚好构成了一个上升序列,设这个上升序列为 $A$
(显然发现其实 $A$ 也是原序列的 $LIS$ 之一)
回到原来的问题,
如果出现不合法的数列,说明存在某一个位置它不管接在当前哪一个下降序列后都是上升的
那么说明它比当前所有下降序列的末尾都大,并且又因为它是当前位置最右的,那么它一定可以接在 $A$ 的后面,
发现此时就找到了一个长度大于 $LIS$ 的上升序列,所以矛盾了
然后就证明完了
所以按着上面的思路搞就行了
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<set>
using namespace std;
typedef long long ll;
inline int read()
{
int x=,f=; char ch=getchar();
while(ch<''||ch>'') { if(ch=='-') f=-; ch=getchar(); }
while(ch>=''&&ch<='') { x=(x<<)+(x<<)+(ch^); ch=getchar(); }
return x*f;
}
const int N=1e5+;
int n,m;
struct BIT {
int t[N];
inline void init() { for(int i=;i<=n;i++) t[i]=; }
inline void add(int x,int v) { while(x<=n) t[x]=max(t[x],v),x+=x&-x; }
inline int ask(int x) { int res=; while(x) res=max(res,t[x]),x-=x&-x; return res; }
}T;
int f[N];
vector <int> V,tmp,ans[N];
int work(int len)
{
T.init(); int mx=;
for(int i=;i<len;i++)
mx=max(mx, f[i]=T.ask(V[i])+ ),
T.add(V[i],f[i]);
return mx;
}
void solve1(int len,int mx)
{
tmp.clear(); int las=N; m++;
for(int i=len-;i>=;i--)
if(f[i]==mx&&V[i]<las)
ans[m].push_back(V[i]),mx--,las=V[i];
else tmp.push_back(V[i]);
reverse(ans[m].begin(),ans[m].end());
V=tmp; reverse(V.begin(),V.end());
}
struct dat {
int id,val;
dat (int _id=,int _val=) { id=_id,val=_val; }
inline bool operator < (const dat &tmp) const {
return val!=tmp.val ? val<tmp.val : id<tmp.id;
}
};
void solve2(int mx)
{
set <dat> S;
for(int i=;i<=mx;i++) S.insert(dat(m+i,N));
for(int i=;i<V.size();i++)
{
auto p = S.lower_bound(dat(-,V[i]));
ans[(*p).id].push_back(V[i]);
S.insert(dat((*p).id,V[i])); S.erase(*p);
}
m+=mx; V.clear();
}
int C2[N],h[N];
int main()
{
for(int i=;i<=;i++) C2[i]=i*(i+)/;
for(int i=;i<;i++)
for(int j=C2[i];j<C2[i+]&&j<N;j++)
h[j]=i;
int T=read();
while(T--)
{
for(int i=;i<=m;i++) ans[i].clear(); m=;
n=read(); for(int i=;i<=n;i++) V.push_back(read());
while(V.size())
{
int len=V.size(),mx=work(len);
if(mx>h[len]) solve1(len,mx);
else { solve2(mx); break; }
}
printf("%d\n",m);
for(int i=;i<=m;i++)
{
printf("%d ",int(ans[i].size()));
for(auto A: ans[i]) printf("%d ",A);
puts("");
}
}
return ;
}
Codeforces 1097E. Egor and an RPG game的更多相关文章
- Codeforces 1097E. Egor and an RPG game 构造
原文链接https://www.cnblogs.com/zhouzhendong/p/CF1097E.html 题解 首先我们求出 $k = f(n) = \max\{x|\frac{x(x+1)}2 ...
- 【CF1097E】Egor and an RPG game(动态规划,贪心)
[CF1097E]Egor and an RPG game(动态规划,贪心) 题面 洛谷 CodeForces 给定一个长度为\(n\)的排列\(a\),定义\(f(n)\)为将一个任意一个长度为\( ...
- CF1097E Egor and an RPG game
最少反链划分数 = 最长链.实现:每次找出所有极大元作为一个反链. 任意长度小于k * (k + 1) / 2的排列都能被划分为不多于k个单调序列.且这是一个紧的上界. 然后这题就可以切了. 题意:给 ...
- codeforces 1097 Hello 2019
又回来了.. A - Gennady and a Card Game 好像没什么可说的了. #include<bits/stdc++.h> using namespace std; cha ...
- Hello 2019 (D~G)
目录 Codeforces 1097 D.Makoto and a Blackboard(DP 期望) E.Egor and an RPG game(思路 LIS Dilworth定理) F.Alex ...
- Educational Codeforces Round 94 (Rated for Div. 2) String Similarity、RPG Protagonist、Binary String Reconstruction、Zigzags 思维
题目链接:String Similarity 题意: 首先题目定义了两个串的相似(串的构成是0.1),如果两个串存在对于一个下标k,它们的值一样,那么这两个串就相似 然后题目给你一个长度为2n-1的串 ...
- Educational Codeforces Round 94 (Rated for Div. 2) B. RPG Protagonist (数学)
题意:你和你的随从去偷剑和战斧,你可以最多可以拿\(p\)重的东西,随从可以拿\(f\)重的东西,总共有\(cnt_{s}\)把剑,\(cnt_{w}\)把战斧,每把剑重\(s\),战斧重\(w\), ...
- CodeForces 527B Error Correct System
Error Correct System Time Limit:2000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I6 ...
- (CodeForces 510C) Fox And Names 拓扑排序
题目链接:http://codeforces.com/problemset/problem/510/C Fox Ciel is going to publish a paper on FOCS (Fo ...
随机推荐
- CF1208D
CF1208D 题意: 给你一个数组,要求支持单点修改和单点查询 解法: 直接线段树搞一搞就没了. CODE: #include<iostream> #include<cstdio& ...
- reGeorg(不需要外网ip的代理)
reGeorg _____ ______ __|___ |__ ______ _____ _____ ______ | | | ___|| ___| || ___|/ \| | | ___| | \ ...
- 线上bug或故障界定及填写规范
[线上故障与线上Bug界定] 一.线上故障: 1. 故障参照公司规范稍做调整: a) 1级故障:资讯首页或主App首页无法打开:多条业务线同时不可用:超过15分钟: b) ...
- mysql 给用户设置权限
grant all on wordpress.* to wordpress@'10.0.0.%' identified by 'wordpress'; all 全部权限 ...
- python小白之字典使用笔记
Python 字典(Dictionary) 字典是一种可变容器模型,且可存储任意类型对象. 每个键值 key=>value 对,用冒号 : 分割 每个键值对之间用逗号 , 分割 整个字典包括 ...
- Android中实现日期时间选择器(DatePicker和TimePicker)
利用Android应用框架提供的DatePicker(日期选择器)和TimePicker(时间选择器),实现日期时间选择器. Dialog的Content布局文件(date_time_dialog.x ...
- Selenium下Chrome配置 (含启动无痕界面)
例子: 设置无界面模式浏览器启动chrome_options = webdriver.ChromeOptions() chrome_options.add_argument('--headless') ...
- nginx反向代理本地 两台web负载均衡 使用ip+端口代理
环境: 本地外网ip:123.58.251.166 .配置index.html网页 [root@host---- conf.d]# cat /web/sing/index.html <h1> ...
- CockroachDB学习笔记——[译]在CockroachDB中如何让在线模式更改成为可能
原文链接:https://www.cockroachlabs.com/blog/how-online-schema-changes-are-possible-in-cockroachdb/ 原作者: ...
- Scala使用备注一
package com.ws.spark.study.scala import java.io.File import org.scalatest.FlatSpec import scala.io.S ...