考虑按顺序暴搜子序列。如果序列中的数两两不同,显然每次给上一个找到的子序列添上后缀最小值,即为下一个要找的子序列。如果不能再加了就回溯继续考虑后缀次小、第三小……值,直到找到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. asp.net调用前台js调用后台代码分享

    asp.net调用前台js调用后台代码分享 C#前台js调用后台代码前台js<script type="text/javascript" language="jav ...

  2. 腾讯内推一面C++

    北邮论坛找个腾讯的内推,没想到那么快就安排面试了.第一次面腾讯,写点东西记录一下吧. 面的是位置服务部门. 去了之后HR先给了两张纸,有三道编程题.第一道是求 二进制中1的个数(考察位运算)(剑指of ...

  3. Highchartsjs使用总结及实时动态刷新图

    柱状图: $('#container').highcharts({ //突显红色柱: series: [ 523, 345, 785, 565, 843,{'color': 'red','y': 30 ...

  4. poj3984 广度搜索BFS

      迷宫问题 Description 定义一个二维数组: int maze[5][5] = { 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1 ...

  5. 安装SQL Server时,提示VS Shell 安装失败,退出代码为 1638。

    在安装SQL Server时,提示“安装 Microsoft Visual C++ 2015 Redistributable 时出错VS Shell 安装失败,退出代码为 1638”. 原因:是由于你 ...

  6. SOAP UI-----测webservice接口

    webservice的请求报文和返回报文都是xml格式的. 使用soapui.storm对webservice接口进行测试,postman无法测. http://www.webxml.com.cn/W ...

  7. 【kindle笔记】之 《鬼吹灯》-9-20

    [kindle笔记]读书记录-总 9-20 日常吐槽 连着几天,基本是一口气读完了鬼吹灯. 想来,也算是阴差阳错了.本来是想看盗墓的,读了几页开头,心想坏了,拷贝错了,这是鬼吹灯-- 讲真的,每每读小 ...

  8. JMeter压测分布式部署

    监控JMeter压力机的性能

  9. JavaScript中的函数和C#中的匿名函数(委托、lambda表达式)

    在js中function是一个一个引用类型,所以可以出现这样的代码: 'use strict'; var compare=function(value1, value2) { if (value1&l ...

  10. Java Hash集合的equals()与hashCode() 方法

    Java 集合实现类,无论是HashSet.HashMap等所有的Hash算法实现的集合类(后面简称Hash集合),加入的对象必须实现 hashCode() 与 equals() 方法,稍微不同的地方 ...