版权声明:Why is everything so heavy? https://blog.csdn.net/lzc504603913/article/details/83042360
题意:给你N个栈,每天从任意一个栈中取出一个数,数在手上每保留一天,价值*365。所有数字拿完后,求手上的数子的最小价值。
解题思路:看到题目,初始数字不大于365,所以很容易想到贪心,每次必然是取这N个栈中,栈顶最小的那个数。
然后就会想到用优先队列维护每个栈的栈顶。但是这样有一个问题,栈顶相同怎么办?那就看第二个数谁大,还一样就看第三个数。所以就要想着怎么给这N个栈动态的排序。所以就联想到了后缀数组。
我们把N个栈拼在一起,按照字符串那样去看待,就会发现,所求得的后缀数组就是我们要求的功能,动态的排序!
我们主要是利用的rank数组,之前的优先队列是维护栈顶的数字,现在优先队列维护的是,栈顶的那个数字所在的栈的排位。每次取排位最小的那个,肯定是对的。
然后用一个没用的数字表示栈空即可,具体看代码!
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 500005;
const ll MOD=1000000007ll;
int wa[MAXN], wb[MAXN], wv[MAXN], JS[MAXN]; //计算SA用的辅助数组
int rk[MAXN], height[MAXN], SA[MAXN]; //三个常用数组
/***后缀数组倍增解法***/
int cmp(int *r, int a, int b, int l)
{
return r[a] == r[b] && r[a + l] == r[b + l];
}
void DA(int *r, int *SA, int n, int m)
{
int i, j, p, *x = wa, *y = wb, *t;
for (i = 0; i < m; i++)
JS[i] = 0;
for (i = 0; i < n; i++)
JS[x[i] = r[i]]++;
for (i = 1; i < m; i++)
JS[i] += JS[i - 1];
for (i = n - 1; i >= 0; i--)
SA[--JS[x[i]]] = i;
for (j = 1, p = 1; p < n; j *= 2, m = p)
{
for (p = 0, i = n - j; i < n; i++)
y[p++] = i;
for (i = 0; i < n; i++)
if (SA[i] >= j)
y[p++] = SA[i] - j;
for (i = 0; i < n; i++)
wv[i] = x[y[i]];
for (i = 0; i < m; i++)
JS[i] = 0;
for (i = 0; i < n; i++)
JS[wv[i]]++;
for (i = 1; i < m; i++)
JS[i] += JS[i - 1];
for (i = n - 1; i >= 0; i--)
SA[--JS[wv[i]]] = y[i];
for (t = x, x = y, y = t, p = 1, x[SA[0]] = 0, i = 1; i < n; i++)
x[SA[i]] = cmp(y, SA[i - 1], SA[i], j) ? p - 1 : p++;
}
for (i = 0; i < n; i++)
rk[SA[i]] = i;
return;
}
/*******************/
int head[MAXN];
int s[MAXN];
struct node{
int v;
bool operator <(const node &a)const{
return rk[head[v]]>rk[head[a.v]];
}
};
priority_queue<node> que;
int main(){
int N;
int now=0;
scanf("%d",&N);
for(int i=1;i<=N;i++){
head[i]=now;//栈顶是字符串的哪个位置
int k,x;
scanf("%d",&k);
for(int i=1;i<=k;i++){
scanf("%d",&x);
s[now++]=x;
}
s[now++]=301;//代表这个栈结束
}
s[now++]=0;
DA(s,SA,now,305);
for(int i=1;i<=N;i++)//先把所有“栈”插入优先队列
{
node v1;
v1.v=i;
que.push(v1);
}
ll ans=0;
while(!que.empty()){
int tp=que.top().v;
que.pop();
ans=(ans*365ll+s[head[tp]])%MOD;//hash思想,计算答案
head[tp]++;//下一个
if(s[head[tp]]!=301)//没到栈底,重新入队
{
node v1;
v1.v=tp;
que.push(v1);
}
}
printf("%lld\n",ans*365ll%MOD);
return 0;
}