第十四届程序设计竞赛 H

发布时间 2023-12-25 18:41:55作者: 不o凡

问题 H: 浙外办会展

此题对时间复杂度的要求好高,数组大小n*k(1e7)和时间复杂度n * k * logk(1e7-1e8)有点极限

思路:
题意从k种选s种,问最小代价
1.我们可以开二维数组ans[n][k],表示每个点i选种类是j的最小代价
2.这个可以bfs,算完之后,只需要sort从小到大,累加求和即可

如果你想到了这里,很遗憾,超时8%

分析,每个点都遍历一下,时间复杂度是n^2 肯定过不了;
考虑优化
我们发现很多点的种类是一样的,相当于多个源点向外扩散,每个点的最小值是距离源点最近的那个点,没错可以利用上次学到的优先队列维护最小值,时间复杂的为n* logn,可以。

一点点细节
int a[N];
int n,m,s,k;
vector<int> g[N];
int ans[N][105];
int vis[N][105];
struct node{
    int dis,id,idx;
    bool operator < (const node &b)const{
        return dis>b.dis;
    }
};
priority_queue<node> q;
int bfs(){
    while(q.size()){
        auto t=q.top();
        q.pop();
        int dis=t.dis,id=t.id,idx=t.idx;
        if(vis[id][idx]) continue;
        vis[id][idx]=1;
        for(int v:g[id]){
            if(ans[id][idx]+1<ans[v][idx]){
                ans[v][idx]=ans[id][idx]+1;
                q.push({ans[v][idx],v,idx});
            }
        }
    }

}
void bu_f(){
    n=read(),m=read(),k=read(),s=read();
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=1;i<=m;i++){
        int x=read(),y=read();
        g[x].push_back(y);
        g[y].push_back(x);
    }
    memset(ans,INF,sizeof ans);
    for(int i=1;i<=n;i++){
        ans[i][a[i]]=0;
        q.push({0,i,a[i]});
    }
    bfs();
    for(int i=1;i<=n;i++){
        sort(ans[i]+1,ans[i]+k+1);
        ll sum=0;
        for(int j=1;j<=s;j++){
            sum+=ans[i][j];
        }
        write(sum);
        printf(" ");
    }
}