欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

2

程序员文章站 2022-05-15 20:51:45
...

2
2
这是一道贪心题(一开始没想到 TAT )
较简单的情况:目前所有栈的栈顶元素互不相同。显然,当前这步的最优解应该选择栈顶元素最小者,将其放入答案队列。 但是,如果两个栈的栈顶元素相同呢?
乍一看,随意选择一个均可,但是你会发现在样例 3(两个栈中的元素分别为 5 1 2 和 5 1 1)中, 如果第一步选择了一号栈的 5,那么最终结果会得出 5 1 2 5 1 1,而最优解应该是先选二号栈的 5,最终结果为 5 1 1 5 1 2。
假设有两个大小均为 2 的栈 a,b ,a中栈顶元素为 p,接下来是 q1;b 中栈顶元素同样为 p,接下来是 q2。 那么,先选哪个栈好呢?模拟一下,发现: 如果 q1=q2,则继续往后考虑。 若 q1<q2​,则先选栈 a 「肯定不会」「得不到」最优解。模拟 p<q1<q2, q1<p<q2,q1<q2<p。 若 q1>q2,则先选栈 b 肯定不会得不到最优解,自行模拟的东西与上面类似。 一言以蔽之: 每次选择字典序最小的栈,将其栈顶的元素放入答案队列。 把总共 NL 个后缀(N 个数组,每个数组有 L 个)搞个后缀数组出来就行了。然后跑一边后缀数组模板。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1050,inf=0x3f3f3f3f;
int n,L,cnt,s[maxn*maxn],fir[maxn],rank[maxn*maxn],tim,qaq[maxn*maxn],tot,tat[maxn*maxn];
struct node
{
 int pos,val;
 bool operator <(const node& rhs)const{return val>rhs.val;}
};
int sa[maxn*maxn],m,x[maxn*maxn],y[maxn*maxn],c[maxn*maxn];
inline void get_sa(int n)
{
 for(int i=1;i<=n;i++) ++c[x[i]=s[i]];
 for(int i=2;i<=m;i++) c[i]+=c[i-1];
 for(int i=n;i>=1;i--) sa[c[x[i]]--]=i;
 for(int len=1;len<=n;len<<=1)
 {
  int num=0;
  for(int i=n-len+1;i<=n;i++) 
   y[++num]=i;
  for(int i=1;i<=n;i++)
   if(sa[i]>len) 
    y[++num]=sa[i]-len;
  for(int i=1;i<=m;i++) 
   c[i]=0;
  for(int i=1;i<=n;i++) 
   ++c[x[i]];
  for(int i=2;i<=m;i++) 
   c[i]+=c[i-1];
  for(int i=n;i>=1;i--) 
   sa[c[x[y[i]]]--]=y[i];
  swap(x,y);
  int tmp=1;x[sa[1]]=1;
  for(int i=2;i<=n;i++)
   x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+len]==y[sa[i-1]+len])?tmp:++tmp;
  if(tmp==n) 
   break;
  m=tmp;
 }
}
priority_queue<node> p;
int main(){
 scanf("%d",&n);
 qaq[tot=1]=inf;
 for(int i=1;i<=n;i++)
 {
  scanf("%d",&L);
  fir[i]=cnt+1;
  tim+=L;
  for(int j=1;j<=L;j++) 
   scanf("%d",&s[++cnt]),qaq[++tot]=s[cnt];
  s[++cnt]=inf;
 }
 sort(qaq+1,qaq+1+tot);
 m=unique(qaq+1,qaq+1+tot)-(qaq+1);
 for(int i=1;i<=cnt;i++)
  tat[i]=s[i],s[i]=lower_bound(qaq+1,qaq+1+m,s[i])-qaq;
 get_sa(cnt);
 for(int i=1;i<=cnt;i++) 
  rank[sa[i]]=i;
 for(int i=1;i<=n;i++) 
  p.push((node){fir[i],rank[fir[i]]});
 for(int i=1;i<=tim;i++)
 {
  node tmp=p.top();
  p.pop();
  printf("%d ",tat[tmp.pos]);
  if(s[tmp.pos+1]!=inf) 
   p.push((node){tmp.pos+1,rank[tmp.pos+1]});
 }
 return 0;
}