1. 程式人生 > >【JZOJ5573】子序列

【JZOJ5573】子序列

Description

這裡寫圖片描述

Solution

考慮現在已經找到字典序第i小的子序列,設它為SabS為前面的序列),它的兩種擴充套件為:
1. Sacc為所在原序列位置在a之後第一個大於或等於b的數)
2. Sabdd為位置在b之後最小的數)
如果對於這些序列設定一個比較函式,那麼就是經典問題:將字典序最小的序列從堆中提出來,加入它的兩個擴充套件到堆中。
我們發現序列長度較長不能儲存,但其實子序列之間有很多字首關係,我們可以使用一棵trie,通過trie上的節點來表示這些子序列。至於兩個子序列的比較,可以通過它們的lca往下一個兒子的大小關係來比較。
堆或優先佇列複雜度O(l

og2n),子序列比較O(log2n),所以總複雜度是O(klog22n)的。
但這個方法常數較大,且不易實現。

於是我們不機械的把所有可能的子序列都丟進堆裡,靠比較來得出序列,我們可以直接構造。

設答案(即最終序列集)為[1,k],對於一段雜湊值相同的序列集區間[l,r],它一定是由同樣[l,r](r<l)中的序列(區間中雜湊值相同)直接構造出來的。
考慮對於一段序列集[l,r],如何構造字典序最小且剛好能接在已有的序列集後。
posx表示x這個序列的結尾在原序列的位置。
列舉posl後嚴格第i大的數字num,找到posl後所有等於num的數字,每一個都嘗試接在[l

,r]後面,就會得到一個新的[l,r],且保證結尾位置遞增。這樣顯然是符合字典序的。

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;++i)
#define fd(i,j,k) for(int i=j;i>=k;--i)
#define ll long long
using namespace std;
const int N=1e5+10;
int
a[N],tot=0; struct tree{ int l,r,x,p; }tr[N*20]; int rt[N],nx[N],mx=0; int wz[N]; int n,K,seed,mo; void insert(int &v,int l,int r,int x){ tr[++tot]=tr[v],v=tot; if(l==r) {tr[v].p=x,tr[v].x++;return;} int mid=(l+r)>>1; a[x]<=mid?insert(tr[v].l,l,mid,x):insert(tr[v].r,mid+1,r,x); tr[v].x=tr[tr[v].l].x+tr[tr[v].r].x; } int find(int v,int l,int r,int x){ if(x>tr[v].x) return 0; if(l==r) return tr[v].p; int mid=(l+r)>>1; return tr[tr[v].l].x<x?find(tr[v].r,mid+1,r,x-tr[tr[v].l].x):find(tr[v].l,l,mid,x); } struct node{ int p; ll hs; }b[N]; int tt=0; void dfs(int l,int r){ int o=b[l].p; fo(i,1,tr[rt[o+1]].x){ int p=find(rt[o+1],1,mx,i),nw=tt,ww=0; for(int j=p;j;j=nx[j]){ ww++; fo(k,l,r) if(j>b[k].p){ b[++tt].p=j,b[tt].hs=(b[k].hs*seed+a[j])%mo; if(tt==K){ fo(ch,1,K) printf("%lld\n",b[ch].hs); exit(0); } } } dfs(nw+1,tt),i+=ww-1; } } int main() { freopen("sequence.in","r",stdin); freopen("sequence.out","w",stdout); scanf("%d %d %d %d",&n,&K,&seed,&mo); fo(i,1,n){ scanf("%d",&a[i]),mx=max(mx,a[i]); nx[wz[a[i]]]=i,wz[a[i]]=i; } nx[0]=0; fd(i,n,1) rt[i]=rt[i+1],insert(rt[i],1,mx,i); dfs(0,0); }

相關推薦

JZOJ5573序列

Description Solution 考慮現在已經找到字典序第i小的子序列,設它為Sab(S為前面的序列),它的兩種擴充套件為: 1. Sac(c為所在原序列位置在a之後第一個大於或等於b

LOJ#6074序列(動態規劃)

【LOJ#6074】子序列(動態規劃) 題面 LOJ 題解 考慮一個暴力\(dp\)。 設\(f[i][c]\)表示當前在第\(i\)位,並且以\(c\)結尾的子序列個數。 那麼假設當前位為\(a\),強制把\(a\)接在所有出現過的子序列後面,再加上一個單獨的\(a\)。 也就是\(f[i][a]=

[TJOI2014]上升序列

這本質上是一個\(dp\) 如果沒有"兩個上升子序列相同,那麼只需要計算一次"這一個性質,那麼就很好做了,我們用\(dp[i]\)表示以\(i\)結尾的上升子序列個數,那麼就有\(dp[i]=\sum_{j=1}^{i-1}dp[j]\) 這個暴力轉移是\(O(n^2)\)的,我們這裡可以直接用樹狀陣列來

bzoj3675[Apio2014]序列分割 斜率優化dp

sof turn col 兩個 led 輸入 分數 包含 class 原文地址:http://www.cnblogs.com/GXZlegend/p/6835179.html 題目描述 小H最近迷上了一個分隔序列的遊戲。在這個遊戲裏,小H需要將一個長度為n的非負整數序列分

BZOJ3992[SDOI2015]序列統計 NTT+多項式快速冪

繼續 -m zoj 幫助 cst div sam [0 程序 【BZOJ3992】[SDOI2015]序列統計 Description 小C有一個集合S,裏面的元素都是小於M的非負整數。他用程序編寫了一個數列生成器,可以生成一個長度為N的數列,數列中的每個數都屬於集

BZOJ1345[Baltic2007]序列問題Sequence 貪心+單調棧

給定 cnblogs sample led 整數 getc mil output 數列 【BZOJ1345】[Baltic2007]序列問題Sequence Description 對於一個給定的序列a1, …, an,我們對它進行一個操作reduce(i

bzoj4540[Hnoi2016]序列 單調棧+離線+掃描線+樹狀數組區間修改

sta 輸出 char algo .com legend 方法 tle leg 題目描述 給出一個序列,多次詢問一個區間的所有子區間最小值之和。 輸入 輸入文件的第一行包含兩個整數n和q,分別代表序列長度和詢問數。接下來一行,包含n個整數,以空格隔開,第i個整數為ai

C# 序列化與反序列

使用 ria tle 輸入 == 必須 mls zab ddr 轉自:https://www.cnblogs.com/lsy131479/p/8371858.html 對象持久化到文本文件,策略是:將對象的屬性值打散,拆解,分別存儲。 序列化: 保存對象的"全景圖" 序

AHOI2009 維護序列 - 線段樹

print dtree 有一個 max color 操作 一個 build main 題目描述 老師交給小可可一個維護數列的任務,現在小可可希望你來幫他完成。 有長為N的數列,不妨設為a1,a2,…,aN 。有如下三種操作形式: (1)把數列中的一段數全部乘

51nod1822 序列求和 V5

IT 4 sum air clu npr vector AI prime ostream 題解 我是zz吧 nonprime[i * prime[j]] = 0 = = 還以為是要卡常,卡了半天就是過不掉 我們來說這道題…… 首先,我們考慮一個\(K^2\)做法 \(f_{

BZOJ1562NOI2009變換序列

#define getchar put long .org void sin stream getchar() 【BZOJ1562】【NOI2009】變換序列 題面 BZOJ 洛谷 這題面寫的是真的醜,還是先手動翻譯成人話。 讓你構造一個\(0..N-1\)的排列\(T\)

題解HNOI2016序列

span 指針 min class div 有用 for 由於 ||   也想了有半天,沒有做出來……實際上做法確實也是十分精妙的。這裏推薦一個blog,個人認為這位博主講得挺好了:Sengxian‘s Blog;   感覺啟示是:首先要加強對

類和父類實現同一個接口的意義

style inf bottom 父類 100% csdn 一個 article mage 原文作者的疑惑和我的一模一樣...所以沒什麽好解釋的,直接截圖參考即可。原文鏈接:子類和父類實現同一個接口的意義 - CSDN博客 https://blog.csdn.net/s33

題解NOI2016序列

hellip 最大化 min 多次 else truct code name bool   Two - pointer 第一題…… 大概就是對於一段連續的區間求解,使用兩個指針不斷卡區間的長度直到區間不滿足條件吧。   這題只要對區間以長度從小

NOIP2015

題目連結 演算法:           鴿鴿鴿了。。。。。   Code: #include<bits/stdc++.h> #define rep(i,j,k) for(int i=j;i<=k;i++

AUOJ1588括號序列

題面 溫神不喜歡括號序列,但是他發現總是有人喜歡出括號序列的題。 為了讓全世界都能感受到他的痛苦,他想要寫一個轉換器:它能把普通的小寫字串轉換成長度相同的合法的括號序列。 在溫神的構思中,這樣的轉換器需要滿足如下兩個條件: 結果的括號序列必須要是合法的,即左右括號必須要是相匹配的。 對於一對

HDU6345串查詢字首和線段樹

題目大意: 題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=6345 求給定串 l l

#Java#1類呼叫父類被重寫的方法

一、程式碼 package com.atguigu.exer1; //========== Son =================== public class Son extends Father { public String str = "

css元素浮動到了父元素外,父元素沒有隨元素自適應高度,如何解決?

正常情況 如果子元素沒有設定浮動(float),父元素的高度會隨著子元素高度的改變而改變的。 設定浮動以後 父元素的高度不會隨著子元素的高度而變化。 例如:在一個ul中定義若干個li,並設定float='left' <!DOCTYPE html> <html lang="en"&g

BZOJ4540 [HNOI2016] 序列(莫隊)

點此看題面 大致題意: 求出一個序列的一段區間中所有子序列最小值之和。 莫隊 這道題其實是一道莫隊題。 但是需要大量的預處理。 預處理 先考慮預處理兩個陣列\(lst_i\)和\(nxt_i\),分別表示在第\(i\)個元素左邊、右邊第一個小於它的元素的位置。 這可以直接用單調棧實現\(