题目链接:https://ac.nowcoder.com/acm/contest/923/E
题目大意:
思路:矩阵中每个元素都是a[i]+b[j],那么如果a[i]和b[j]都越小,那么这个矩阵元素值就越小。
用multiset维护一下,a[i]和b[i]。每次查询时,优先队列暴力得到前k个就行了。
重点讲一下:优先队列暴力
优先队列的状态为:
struct node
{
multiset<int>::iterator a,b;
bool operator<(const node &c)const
{
return ((*a)+(*b))>((*c.a)+(*c.b));
}
} x,tp;
如果当前最小值为{1, 1}那么比{1, 1}稍微大的数只能是{1, 2}或者{2, 1}。当时不能由一个状态转移到两个状态。会出现状态重复。因为如果这样的话,{1, 2},{2, 1}都能够转化到{2, 2}那么{2, 2}就重复出现在队列中。
我们要对转化加限制。
我们现在证明一下正确性:
可以自己画图理解一下:
对于一个出现的状态{x, y}, 队列中如果有{x, z}, {z<y}的状态存在,那么对于{x, y} y!=1扩展出{x, y+1}肯定不是最优解。
如果没有那么说明{x, y+1} 已经扩展出来了。更不用去扩展了。
#include<bits/stdc++.h>
using namespace std;
#define N 101010
#define ll long long
#define go(i,a,b) for(int i=a;i<=b;i++)
int n,m,zzz,a[N],b[N],op,nowx,nowy;
struct node
{
multiset<int>::iterator a,b;
bool operator<(const node &c)const
{
return ((*a)+(*b))>((*c.a)+(*c.b));
}
} x,tp;
multiset<int>r,c;
priority_queue<node>q;
char s[15];
int main()
{
scanf("%d%d%d",&n,&m,&zzz);
go(i,0,n-1)scanf("%d",&a[i]);
go(i,0,m-1)scanf("%d",&b[i]);
c.insert(b[0]),r.insert(a[0]);
go(qq,1,zzz)
{
scanf("%s%d",s,&op);
if(s[0]=='Q')
{
x.a=r.begin();
x.b=c.begin();
q.push(x);
while(op--)
{
tp=q.top();
q.pop();
printf("%d%c",*(tp.a)+*(tp.b),op==0?'\n':' ');
x=tp;
tp.a++;
if(tp.a!=r.end())
q.push(tp);
if(x.a==r.begin())//保证b[i](i=1)
{
x.b++;
if(x.b!=c.end())
q.push(x);
}
}
while(!q.empty())
q.pop();
}
else if(s[0]=='R')
{
int i=nowy+1;
nowy=min(nowy+op,m-1);
for(i; i<=nowy; i++)
c.insert(b[i]);
}
else if(s[0]=='D')
{
int i=nowx+1;
nowx=min(nowx+op,n-1);
for(i; i<=nowx; i++)
r.insert(a[i]);
}
}
return 0;
}