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 ...
随机推荐
- PHP+CI框架+Memcache集成
一.目录结构 二.具体代码 MemcacheCluster.php <?php /** * 一致性哈希memcache分布式,采用的是虚拟节点的方式解决分布均匀性问题,查找节点采用二分法快速查找 ...
- centos7中oracle数据库安装和卸载
参考: 完全命令行安装(验证可行):https://jingyan.baidu.com/article/90895e0f29c92164ec6b0bd1.html 存在疑问:是否需要jdk的配置(因为 ...
- mvc partialView断点调试问题
mvc中的partialview 在前端f12调试时,默认看不到代码的. 在Js中加上debugger; 调试时会走到断点,多出个VM打头的局部视图页面.
- Linux使用iptables设置黑白名单
使用ipset工具 1,下面我先说下iptables的基本配置规则,然后再说ipset以下使用C7 x86_64为实验环境CentOS7默认的防火墙不是iptables,而是firewalle.如果你 ...
- Swift 析构过程
在一个类的实例被释放之前,析构函数被立即调用.用关键字deinit来标示析构函数,类似于初始化函数用init来标示.析构函数只适用于类类型. 析构过程原理 Swift 会自动释放不再需要的实例以释放资 ...
- 通过OpenCL内核代码猜测设备寄存器个数
在OpenCL标准中,没有给出查看计算设备一共有多少寄存器,至少能分配给每个work-item多少寄存器使用的特征查询.而由于一个段内核代码是否因寄存器紧缺而导致性能严重下降也是一个比较重要的因素,因 ...
- mac下不允许安装除了app store之外的软件设置:
1.dock栏的系统偏好设置. 2.找到安全性与隐私 3.点击面板中的通用,在点击左小角的锁按钮, 4.选择任何来源,确定就可以了.[如果只有两个选项,而没有任何来源的话,打开终端,执行:sudo s ...
- Cloudera Manager 概念
cloudera公司发布的CDH集群,使用Cloudera Manager来管理整个集群,使用过程中主要涉及到几个关键概念:cluster.service.role.host.直接上图,直观理解几个概 ...
- MSMQ菜鸟教程
一 .MSMQ概述 MSMQ全称MicroSoft Message Queue,微软消息队列,是在多个不同的应用之间实现相互通信的一种异步传输模式,相互通信的应用可以分布于同一台机器上,也可以分布于 ...
- TextView的封装和自定义
实现的效果如下: #import <UIKit/UIKit.h> @interface CustomTextView : UITextView @property (nonatomic , ...