#194 sequence(搜索+动态规划+主席树)
考虑按顺序暴搜子序列。如果序列中的数两两不同,显然每次给上一个找到的子序列添上后缀最小值,即为下一个要找的子序列。如果不能再加了就回溯继续考虑后缀次小、第三小……值,直到找到k个子序列。
有重复的数后,考虑后缀k小值只取第一次出现的位置,并在每找到一个子序列后就统计其出现次数。显然这样就能找到所有要找的子序列,因为序列末端选择位置更靠前,后面的选择更多。
求一个序列在另一个序列里的出现次数显然可以dp,即设f[i][j]为第一个序列的i位置和第二个序列的j位置匹配的方案数。当然答案序列可能很长,dp数组可能开不下,不过注意到有ai<=30的部分分,可以猜想这个部分的答案序列长度不会很长,先考虑拿部分分。
每找到一个序列就暴力dp即为O(n2k)。注意到dp时可以直接继承上层dfs的dp数组,于是复杂度O(nk)。这里的k一般来说并不能跑满,实际上是本质不同的答案中出现的子序列个数。但是很容易卡满,比如放99970个30,最后将1到30倒序加入序列,这样每个答案序列都是不同的,就被卡成暴力了。
但上面这个hack数据有比较特殊的地方,即存在于答案中的数字基本上出现次数很少。注意到我们之前的dp实际上可以将做一次的复杂度优化到序列最后一个数的出现次数(*log)。并且dp时可以直接从搜到的位置开始。这样上面的数据就hack不掉了。同时如果要接着hack这个做法,使dp部分运算次数增加,本质不同的答案子序列数量又会减少。这样这个做法就根本卡不掉并且跑得飞快了,复杂度O(玄学)。
但实际上可以冷静分析一下复杂度,如果某次dp时该数dp值不为0的位置个数为x(显然因为是从搜到的位置开始的,dp值均>0),我们至少就找到了x个答案中的子序列。所以这一部分复杂度其实是O(k)(*log)的。大概就是所谓卡常卡着卡着发现复杂度对了?
还剩下一点问题,就是上面的dp数组开不下,以及要找后缀k小值。第一个问题直接对dp数组开vector,显然空间是线性的。第二个是主席树板子题。总复杂度O(klogn)。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define N 100010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
int n,m,V,a[N],root[N],nxt[N],p[N],seed,P,tot,cnt;
vector<int> pos[N],f[N];
struct data{int l,r,x,pos;
}tree[N<<6];
void ins(int &k,int l,int r,int x,int p)
{
tree[++cnt]=tree[k];k=cnt;
if (l==r) {tree[k].x=1,tree[k].pos=p;return;}
int mid=l+r>>1;
if (x<=mid) ins(tree[k].l,l,mid,x,p);
else ins(tree[k].r,mid+1,r,x,p);
tree[k].x=tree[tree[k].l].x+tree[tree[k].r].x;
}
int query(int k,int l,int r,int x)
{
if (l==r) return tree[k].pos;
int mid=l+r>>1;
if (x<=tree[tree[k].l].x) return query(tree[k].l,l,mid,x);
else return query(tree[k].r,mid+1,r,x-tree[tree[k].l].x);
}
int findnxt(int k,int x){return query(root[k+1],0,V,x);}
int findpre(int x,int k){return lower_bound(pos[x].begin(),pos[x].end(),k)-pos[x].begin()-1;}
void dfs(int k,int cur,int h)
{
int last=0;
while (tot<m&&k<n)
{
last++;int u=findnxt(k,last);
if (u>n) break;
int H=(1ll*h*seed+a[u])%P;
f[cur+1].clear();pos[cur+1].clear();
for (int i=u,cnt=0;i<=n;i=nxt[i],cnt++)
{
pos[cur+1].push_back(i);
if (i!=u) f[cur+1].push_back(f[cur+1][cnt-1]);
else f[cur+1].push_back(0);
int x=findpre(cur,i);
if (x>=0) f[cur+1][cnt]+=f[cur][x];
f[cur+1][cnt]=min(f[cur+1][cnt],m-tot);
}
int v=f[cur+1][f[cur+1].size()-1];
for (int i=1;i<=v;i++) printf("%d\n",H);
tot+=v;
dfs(u,cur+1,H);
}
}
int main()
{
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
n=read(),m=read(),seed=read(),P=read();
for (int i=1;i<=n;i++) V=max(V,a[i]=read());
V++;a[n+1]=V;
root[n+2]=0;
for (int i=n+1;i>=1;i--)
{
root[i]=root[i+1];
ins(root[i],0,V,a[i],i);
}
nxt[n+1]=n+1;for (int i=0;i<=V;i++) p[i]=n+1;
for (int i=n;i>=0;i--) nxt[i]=p[a[i]],p[a[i]]=i;
f[0].push_back(1);pos[0].push_back(0);
dfs(0,0,0);
return 0;
}
#194 sequence(搜索+动态规划+主席树)的更多相关文章
- HDU 5919 -- Sequence II (主席树)
题意: 给一串数字,每个数字的位置是这个数第一次出现的位置. 每个询问对于序列的一个子区间,设一共有k个不同的数,求第ceil(k/2)个数的位置. 因为强制在线,所以离线乱搞pass掉. 主席树可解 ...
- HDU 5919 Sequence II(主席树)题解
题意:有A1 ~ An组成的数组,给你l r,L = min((l + ans[i - 1]) % n + 1, (r + ans[i - 1]) % n + 1),R = max((l + ans[ ...
- HDU--5519 Sequence II (主席树)
题目链接 2016年长春ccpc I 题 题目大意 : 给你n(n≤2∗105n≤2∗105)个数,每个数的大小 0<Ai≤2∗10^5 0<Ai≤2∗10^5. 再给你m(m≤2∗1 ...
- HDU 5919 Sequence II(主席树+逆序思想)
Sequence II Time Limit: 9000/4500 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) To ...
- HDU 5919 Sequence II(主席树+区间不同数个数+区间第k小)
http://acm.split.hdu.edu.cn/showproblem.php?pid=5919 题意:给出一串序列,每次给出区间,求出该区间内不同数的个数k和第一个数出现的位置(将这些位置组 ...
- HDU 5919 Sequence II 主席树
Sequence II Problem Description Mr. Frog has an integer sequence of length n, which can be denoted ...
- Sequence II HDU - 5919(主席树)
Mr. Frog has an integer sequence of length n, which can be denoted as a1,a2,⋯,ana1,a2,⋯,anThere are ...
- HDU5919 Sequence II(主席树)
Mr. Frog has an integer sequence of length n, which can be denoted as a1,a2,⋯,ana1,a2,⋯,anThere are ...
- 【CodeForces】960 F. Pathwalks 主席树+动态规划
[题目]F. Pathwalks [题意]给定n个点m条边的有向图,可能不连通有重边有自环.每条边有编号 i 和边权 wi ,求最长的路径(可以经过重复节点)满足编号和边权都严格递增.n,m,wi&l ...
随机推荐
- .net core实践系列之SSO-同域实现
前言 SSO的系列还是以.Net Core作为实践例子与大家分享,SSO在Web方面复杂度分同域与跨域.本篇先分享同域的设计与实现,跨域将在下篇与大家分享. 如有需要调试demo的,可把SSO项目部署 ...
- 自建 Gitlab (邮箱配置、拆分 PostgreSQL、Redis) + 随想
前言 最近折腾了一番自建 gitlab,在此做个记录,供君参考.整个构建过程基于 Docker Swarm(近期有计划将微服务移植到 Kubernetes,但还没倒腾顺手,暂时先沿用旧的方案),主题配 ...
- Misha, Grisha and Underground CodeForces - 832D (倍增树上求LCA)
Misha and Grisha are funny boys, so they like to use new underground. The underground has n stations ...
- 用PhoneGap创建第一个项目
1.在eclipse中新建Android Project2.在项目的目录下,建两个文件夹:/libs/assets/www3.进入将刚刚下载并解压的PhoneGap包里Anroid目录,我们需要的资源 ...
- anaconda 出现add 。。。进不去
找到.condarc 文件 C:\Users\leiyi内 把里面内容替换为 channels: - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pk ...
- 使用PHPExcel导出数据库表结构及内容
导出表结构: mysql> desc user ; +----------+--------------+------+-----+---------------------+--------- ...
- PAT L3-007 天梯地图
https://pintia.cn/problem-sets/994805046380707840/problems/994805051153825792 本题要求你实现一个天梯赛专属在线地图,队员输 ...
- TCP 握手和挥手图解(有限状态机)
1.引言 TCP 这段看过好几遍,老是记不住,没办法找工作涉及到网络编程这块,各种问 TCP .今天好好整理一下握手和挥手过程.献给跟我一样忙碌,找工作的童鞋,欢迎大神批评指正. 2.TCP 的连接建 ...
- 如何入门vue之二
学习完指令之后我们需要学习的就是组件. 在学习组件前我们要了解一下 methods 用来处理事件的. computed用来计算属性 他就是类似于data一样只不过是动态的处理数据 里面写的方法当成属 ...
- Es6数值拓展
Es6数值拓展 一,Number扩展 1,ES6 提供了二进制和八进制数值的新的写法,分别用前缀0b(或0B)和0o(或0O)表示. 将0b和0o前缀的字符串数值转为十进制,要使用Number方法 N ...