郑州轻工业大学筑梯杯补题

补题链接https://ac.nowcoder.com/acm/contest/106899/
作为外校参赛的,清明节放假花一天时间去比赛,在这里记录一下补的几个题

C.简单题

给定一个由n个正整数组成的序列a,求其所有连续子序列中按字典序排序后的第 k 大的连续子序列。
说是简单题,也没那么简单
由于字典序比较大小发现一位不同就可以确定以前面相同为前缀的所有连续子序列大小,可以记录每个数为开头有多少种序列,用k一个一个减掉就可以快速找出这一位
以此类推,找到一位后从下一位可能的所有位置按照之前步骤在确定一位就行了。

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define lowbit(x) = ((x)& - (x))
#define rep(a,b,c) for(int a=b;a<=c;a++)
#define per(a,b,c) for(int a=b;a>=c;a--)
#define x first
#define y second
using namespace std;
typedef long long ll;

const int N = 5e3+3;
int n,k;
int a[N],b[N];
vector<int> pos,pos2;
map<int,int> mp;
int solve(vector<int>& p){
    //int len = p.size();
    //cout<<p.size();
    if(k<=p.size())return 0;
    k-=p.size();
    map<int,int>mp2;
    vector<int> v;
    for(auto &i:p){
    	if(i!=n){
    	    mp2[a[i+1]]+=n-i;
        	v.emplace_back(a[i+1]);	
		}

    }
    sort(v.begin(),v.end());
    int siz = unique(v.begin(),v.end())-v.begin();
    int q = 0;
    while(k-mp2[v[q]]>0){
        k -= mp2[v[q]];
        q++;
    }
    return v[q];
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>n>>k;
    k = n*(n+1)/2-k+1;
    rep(i,1,n){
        cin>>a[i];
        b[i] = a[i];
    }
    rep(i,1,n){
        mp[a[i]]+=n-i+1;
        //q.emplace(a[i]);
    }
    sort(b+1,b+n+1);
    int len = unique(b+1,b+n+1)-b-1;
    int p = 1;
    while(k-mp[b[p]]>0){
        k-=mp[b[p]];
        ++p;
    }
    rep(i,1,n)if(a[i] == b[p])pos.emplace_back(i);
    //for(auto &i:pos)cout<<i<<' ';
    cout<<b[p]<<' ';
    while(k>0){
        int now = solve(pos);
        if(now == 0)break;
        cout<<now<<' ';
        for(auto &i:pos){
            if(i!=n&&a[i+1] == now){
                pos2.emplace_back(i+1);
            }
        }
        swap(pos,pos2);
        pos2.clear();
    }
	return 0;
}

K.计算机的末路

迪杰斯特拉算法+3进制状压dp
你是外卖糕手吗?
这个城市由 n 个街区组成,街区之间由 m 条双向道路相连,每条道路的通行时间为t。
你的起始位置是 p,现在有 k 份外卖订单,每份订单包含一个取餐点 s 和一个送餐点 t,其中 s!=t。
对于每份订单,你必须先前往取餐点取餐,然后才能前往送餐点完成送餐。你的电动车可以同时装多份外卖,请计算完成所有外卖订单所需的最短时间。
保证这个城市的街区是连通的,即任意两个街区之间至少有一条路径可达。可能存在重边和自环。

这题补了一晚自习+晚加班1hdebug+早上最后修改,及其痛苦

看了题解做的,关键在于k<=10,先预处理初始点,取货点,送货点相互之间的最短路,再用3进制储存每件货物状态,0,1,2分别代表未取货,取货未送达,已完成
最多10件货物就是3^10大概是60000个状态,再添加一维表示该状态的站立点,60000*20个状态,在此基础上进行dp
每个状态对每个订单的进度可以转移状态

时间复杂度o(3^k * k^2 + k*nlogm)

#include<bits/stdc++.h>
#define lowbit(x) = ((x)& - (x))
#define rep(a,b,c) for(int a=b;a<=c;a++)
#define per(a,b,c) for(int a=b;a>=c;a--)
#define x first
#define y second
using namespace std;
typedef long long ll;

const int N = 1e5+4;
const ll INF = 1e18;

struct edge{
    int to;
    ll val;

};
struct node{
    int u;
    ll dis;
    bool operator < (const node& x) const{
        return dis>x.dis;
    }
};
vector<edge> e[N];
int n,m,k,p;
int s[12],t[12];
int vis[N],pow3[12];
ll dist[N],pdis[22][22],dp[60000][22];

void dij(int x){
    //vis[x] = 1;
    dist[x] = 0;
    node now;
    priority_queue<node> q;
    q.emplace(node{x,0});
    while(!q.empty()){
        now = q.top();
        q.pop();
        if(vis[now.u])continue;
        vis[now.u] = 1;
        for(auto &i:e[now.u]){
            if(vis[i.to])continue;
            if(dist[i.to]>now.dis+i.val){
                dist[i.to] = now.dis+i.val;
                q.emplace(node{i.to,dist[i.to]});
            }
        }
    }
}
void init1(){
    pow3[0] = 1;
    rep(i,1,11)pow3[i] = 3*pow3[i-1];
    rep(i,0,59999){
    	rep(j,0,21)dp[i][j] = INF;
	}
}
void init2(){
    memset(vis,0,sizeof(vis));
    rep(i,1,n)dist[i] = INF;
}
int calc(int x,int p){
    return (x/pow3[p])%3;
}

void dfs(int x,int pos){
    int tmp;ll res;
    rep(i,0,k-1){
        tmp = calc(x,i);
        if(tmp == 0){
        	res = dp[x][pos]+pdis[pos][i];
        	if(res<dp[x+pow3[i]][i]){
        		dp[x+pow3[i]][i] = res;
        		dfs(x+pow3[i],i);
			}
        }
        if(tmp == 1){
        	res = dp[x][pos]+pdis[pos][i+10];
        	if(res<dp[x+pow3[i]][i+10]){
        		dp[x+pow3[i]][i+10] = res;
        		dfs(x+pow3[i],i+10);
			}
        	//res = val+pdis[pos][i+10];
            //dp[x+pow3[i]] = min(dp[x+pow3[i]],res);
            //dfs(x+pow3[i],i+10,res);
        }
    }
}

void solve(){
    rep(i,0,k-1){
        dfs(pow3[i],i);
    }
}

int main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>n>>m>>k>>p;
    
    int u,v;ll t1;
    rep(i,1,m){
        
        cin>>u>>v>>t1;
        if(u == v)continue;
        e[u].emplace_back(edge{v,t1});
        e[v].emplace_back(edge{u,t1});
    }
    rep(i,0,k-1)cin>>s[i]>>t[i];
    init1();
    init2();
    dij(p);
    rep(i,0,k-1){
        dp[pow3[i]][i] = dist[s[i]];
        //pdis[0][]
        //cout<<dist[s[i]]<<' ';
    }
    rep(i,0,k-1){
        init2();
        dij(s[i]);
        rep(j,0,k-1){
            pdis[i][j] = dist[s[j]];
            pdis[j][i] = pdis[i][j];
        }
        rep(j,10,9+k){
            pdis[i][j] = dist[t[j-10]];
            pdis[j][i] = pdis[i][j];
        }
    }
    rep(i,10,9+k){
        init2();
        dij(t[i-10]);
        rep(j,0,k-1){
            pdis[i][j] = dist[s[j]];
            pdis[j][i] = pdis[i][j];
        }
        rep(j,10,9+k){
            pdis[i][j] = dist[t[j-10]];
            pdis[j][i] = pdis[i][j];
        }
    }
    solve();
    ll ans = INF;
    
    rep(i,10,9+k)ans = min(ans,dp[pow3[k]-1][i]);
    cout<<ans;
	return 0;
}

比赛时还有个j题踢足球模拟没出,不过队友打的我就懒得补啦

posted @ 2025-04-13 15:13  明天能下雨吗  阅读(45)  评论(0)    收藏  举报