好把我竟然打了lj的题解方法。
代码长常数大。
大概就是用个优先队列来维护。
每次提出最小的。
考虑两种转移:
1.在它后面加个最小的。
2.把它的最后一个删掉,找个次小的。
第一种转移预处理。
可以用主席树来维护第二种转移。
比较大小的话就用trie上倍增。
Code:
#pragma G++ optimize (2)
#include
#include
#include
#include
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define fd(i, x, y) for(int i = x; i >= y; i --)
#define low(a) ((a) & -(a))
using namespace std;
const int C = 1e5;
const int N = 1e5 + 5, M = 1e7 + 5;
int n, k, seed, mo, a[N];
int t[M][2], w[M], tt;
struct tree {
int pl, pr, rt;
void dg(int &i, int x, int y) {
if(!i) i = ++ tt;
if(x == y) {if(!w[i]) w[i] = pr; return;}
int m = x + y >> 1;
if(pl <= m) dg(t[i][0], x, m); else dg(t[i][1], m + 1, y);
w[i] = w[t[i][0]] | w[t[i][1]];
}
int dd(int &i, int x, int y) {
if(!w[i] || y < pl || x > pr) return 0;
if(x == y) return w[i];
int m = x + y >> 1, p = dd(t[i][0], x, m);
return p ? p : dd(t[i][1], m + 1, y);
}
int fi(int l, int r) {pl = l; pr = r; return dd(rt, 1, C);}
} tr[N];
int find(int x, int l, int r) {
int ans = n + 1; x = n - x + 1;
while(x) {
int p = tr[x].fi(l, r);
if(p && (a[p] < a[ans] || a[p] == a[ans] && p < ans)) ans = p;
x -= low(x);
}
return ans;
}
int ss[N * 2];
int fa[17][N * 2];
map<int, int> son[N * 2]; int td = 1, dep[N * 2], z[N * 2];
int add(int x, int c) {
if(son[x][c]) return son[x][c];
son[x][c] = ++ td;
dep[td] = dep[x] + 1; z[td] = c;
fa[0][td] = x; fo(i, 1, 16) fa[i][td] = fa[i - 1][fa[i - 1][td]];
ss[td] = ((ll) ss[x] * seed + c) % mo;
return td;
}
struct node {
int x, f, t;
node(int X, int F, int T) {x = X, f = F, t = T;}
node() {}
};
int log2[N];
bool operator < (node a, node b) {
int t1 = a.t, t2 = b.t, p = max(log2[dep[t1]], log2[dep[t2]]);
if(dep[t1] > dep[t2]) {
fd(i, p, 0) if(dep[fa[i][t1]] >= dep[t2]) t1 = fa[i][t1];
}
else
fd(i, p, 0) if(dep[fa[i][t2]] >= dep[t1]) t2 = fa[i][t2];
if(t1 == t2) return dep[a.t] > dep[b.t];
fd(i, p, 0) if(fa[i][t1] != fa[i][t2]) t1 = fa[i][t1], t2 = fa[i][t2];
return z[t1] > z[t2];
} //remember have rev
priority_queue q;
int fi[N], nt[N], te[N];
void read(int &n)
{
char ch=' ';
for(; ch < '0' || ch > '9'; ch = getchar());
for(;ch>='0' && ch<='9';ch=getchar())n=n*10+ch-48;
}
void write(int x) {
if(x == 0) putchar('0');
int d[10]; d[0] = 0;
while(x) d[++ d[0]] = x % 10, x /= 10;
for(; d[0]; d[0] --) putchar(d[d[0]] + '0');
putchar('\n');
}
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) read(a[i]);
fo(i, 1, 16) log2[1 << i] = 1;
fo(i, 1, n) log2[i] += log2[i - 1];
a[n + 1] = 1e9;
fd(i, n, 1) {
nt[i] = fi[a[i]];
fi[a[i]] = i;
}
{
int xx = n + 1;
fd(i, n, 0) {
te[i] = xx;
if(a[i] <= a[xx]) xx = i;
}
}
fo(i, 1, n) {
int x = n - i + 1;
while(x <= n) {
tr[x].pl = a[i]; tr[x].pr = i;
tr[x].dg(tr[x].rt, 1, C);
x += low(x);
}
}
// return 0;
q.push(node(0, 0, 1));
fo(ii, 1, k + 1) {
node c = q.top(); q.pop();
if(c.x) write(ss[c.t]);
int x = te[c.x];
if(x <= n) q.push(node(x, c.x, add(c.t, a[x])));
if(!c.x) continue;
x = nt[c.x];
if(!x) x = find(c.f + 1, a[c.x] + 1, C);
if(x <= n) q.push(node(x, c.f, add(fa[0][c.t], a[x])));
}
}