luogu P6230 [BalticOI 2019 Day2]奥运会
题面传送门
看到题面的瞬间想到超级钢琴。
然后写了个类似超级钢琴的东西发现会有重复然后就不知道怎么办了。
被题解点播了一下。
就是先跑出最优解,然后看最优解前\(k\)个不动拿来拓展,这样每个分支不交就可以堆维护了。
时间复杂度\(O(Ck^2(n+k)+ClogClogk)\)
code:
#include<cstdio>
#include<queue>
#include<algorithm>
#include<bitset>
#define N 500
#define K 6
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int n,k,C,a[N+5][K+5],now;
struct ques{
int w,vis[K+5],last;bitset<N+5> g;
bool operator <(const ques s)const{return w<s.w;}
}tmp,pus;
priority_queue<ques> q;
struct yyy{int w,id;}b[K+5][N+5];
I bool cmp(yyy x,yyy y){return x.w>y.w;}
I void get(ques &x,int k){for(int i=1;i<=n;i++) if(!x.g[b[k][i].id]){x.g[b[k][i].id]=1;x.vis[k]=b[k][i].id;break;}}
I void calc(ques &x){
register int i,j,pus;x.w=0;
for(i=1;i<=k;i++){
for(pus=0,j=1;j<=i;j++) pus=max(pus,a[x.vis[j]][i]); x.w+=pus;
}
}
int main(){
// freopen("olymp.in","r",stdin);freopen("olymp.out","w",stdout);
register int i,j;scanf("%d%d%d",&n,&k,&C);
for(i=1;i<=n;i++){
for(j=1;j<=k;j++) scanf("%d",&a[i][j]),b[j][i]=(yyy){a[i][j],i};
}
for(i=1;i<=k;i++) sort(b[i]+1,b[i]+n+1,cmp);
for(i=1;i<=k;i++)get(tmp,i);tmp.last=1;calc(tmp);q.push(tmp);
while(--C){
tmp=q.top();q.pop();if(tmp.g.count()==n) continue;//printf("%d\n",tmp.w);for(i=1;i<=k;i++) printf("%d ",tmp.vis[i]);printf("\n");
for(i=k;i>=tmp.last;i--){
pus=tmp;pus.last=i;for(j=i;j<=k;j++) get(pus,j);calc(pus);q.push(pus);//printf("insert %d %d %d %d\n",pus.w,i,pus.vis[1],pus.vis[2]);
tmp.g[tmp.vis[i]]=0;tmp.vis[i]=0;
}
}
printf("%d\n",q.top().w);
}