考虑按顺序暴搜子序列。如果序列中的数两两不同,显然每次给上一个找到的子序列添上后缀最小值,即为下一个要找的子序列。如果不能再加了就回溯继续考虑后缀次小、第三小……值,直到找到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(搜索+动态规划+主席树)的更多相关文章

  1. HDU 5919 -- Sequence II (主席树)

    题意: 给一串数字,每个数字的位置是这个数第一次出现的位置. 每个询问对于序列的一个子区间,设一共有k个不同的数,求第ceil(k/2)个数的位置. 因为强制在线,所以离线乱搞pass掉. 主席树可解 ...

  2. 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[ ...

  3. 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 ...

  4. HDU 5919 Sequence II(主席树+逆序思想)

    Sequence II Time Limit: 9000/4500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) To ...

  5. HDU 5919 Sequence II(主席树+区间不同数个数+区间第k小)

    http://acm.split.hdu.edu.cn/showproblem.php?pid=5919 题意:给出一串序列,每次给出区间,求出该区间内不同数的个数k和第一个数出现的位置(将这些位置组 ...

  6. HDU 5919 Sequence II 主席树

    Sequence II Problem Description   Mr. Frog has an integer sequence of length n, which can be denoted ...

  7. Sequence II HDU - 5919(主席树)

    Mr. Frog has an integer sequence of length n, which can be denoted as a1,a2,⋯,ana1,a2,⋯,anThere are ...

  8. HDU5919 Sequence II(主席树)

    Mr. Frog has an integer sequence of length n, which can be denoted as a1,a2,⋯,ana1,a2,⋯,anThere are ...

  9. 【CodeForces】960 F. Pathwalks 主席树+动态规划

    [题目]F. Pathwalks [题意]给定n个点m条边的有向图,可能不连通有重边有自环.每条边有编号 i 和边权 wi ,求最长的路径(可以经过重复节点)满足编号和边权都严格递增.n,m,wi&l ...

随机推荐

  1. .net core实践系列之SSO-同域实现

    前言 SSO的系列还是以.Net Core作为实践例子与大家分享,SSO在Web方面复杂度分同域与跨域.本篇先分享同域的设计与实现,跨域将在下篇与大家分享. 如有需要调试demo的,可把SSO项目部署 ...

  2. 自建 Gitlab (邮箱配置、拆分 PostgreSQL、Redis) + 随想

    前言 最近折腾了一番自建 gitlab,在此做个记录,供君参考.整个构建过程基于 Docker Swarm(近期有计划将微服务移植到 Kubernetes,但还没倒腾顺手,暂时先沿用旧的方案),主题配 ...

  3. 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 ...

  4. 用PhoneGap创建第一个项目

    1.在eclipse中新建Android Project2.在项目的目录下,建两个文件夹:/libs/assets/www3.进入将刚刚下载并解压的PhoneGap包里Anroid目录,我们需要的资源 ...

  5. anaconda 出现add 。。。进不去

    找到.condarc 文件  C:\Users\leiyi内 把里面内容替换为 channels: - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pk ...

  6. 使用PHPExcel导出数据库表结构及内容

    导出表结构: mysql> desc user ; +----------+--------------+------+-----+---------------------+--------- ...

  7. PAT L3-007 天梯地图

    https://pintia.cn/problem-sets/994805046380707840/problems/994805051153825792 本题要求你实现一个天梯赛专属在线地图,队员输 ...

  8. TCP 握手和挥手图解(有限状态机)

    1.引言 TCP 这段看过好几遍,老是记不住,没办法找工作涉及到网络编程这块,各种问 TCP .今天好好整理一下握手和挥手过程.献给跟我一样忙碌,找工作的童鞋,欢迎大神批评指正. 2.TCP 的连接建 ...

  9. 如何入门vue之二

    学习完指令之后我们需要学习的就是组件. 在学习组件前我们要了解一下 methods 用来处理事件的. computed用来计算属性  他就是类似于data一样只不过是动态的处理数据 里面写的方法当成属 ...

  10. Es6数值拓展

    Es6数值拓展 一,Number扩展 1,ES6 提供了二进制和八进制数值的新的写法,分别用前缀0b(或0B)和0o(或0O)表示. 将0b和0o前缀的字符串数值转为十进制,要使用Number方法 N ...