CSP-S2023完善程序解析

题目链接:https://mp.weixin.qq.com/s/H3H8S1UYb9f3ga7oc5DbmQ 

一.本题使用了拓扑排序,计算出路径条数f,并每次依次减去路径条数,每减一次,就得到了路径上的一个点,最终形成了一条路经

34.这里的next函数,查找了路径上的下一个点,依次减去u的路径条数,直到不能减为止,故选B

35.此处求的是拓扑序,又因后面已有deg[u]--,故选A

36.此处求解了路径条数,使用加法原理,可得出f[u]=1+∑f[v],故选A

37.这里求解了路径上的每个点,当k>1时,求解下一个点,当k=1时,就不用在求解了,故选D

38.此处是对k进行修改,字典序最小的路径一定是终点为自身的,所以要减一,故选C

完整代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e6+39+7;
int n,m,deg[N];ll k,f[N];
vector<int>G[N];
int next(vector<int>E,ll &k){
	sort(E.begin(),E.end());
	for(int x:E){
		if(k<=f[x])return x;
		k-=f[x];
	}
	return -1;
}
int main(){
	cin>>n>>m>>k;
	for(int i=0;i<m;i++){
		int x,y;cin>>x>>y;
		G[x].push_back(y);
		deg[y]++;
	}
	vector<int>q;
	for(int i=0;i<n;i++)if(!deg[i])q.push_back(i);
	for(int i=0;i<n;i++){
		int x=q[i];
		for(int y:G[x]){
			if(deg[y]==1)q.push_back(y);
			deg[y]--;
		}
	}
	reverse(q.begin(),q.end());
	for(int u:q){
		f[u]=1;
		for(int v:G[u])f[u]=min(f[u],(ll)1e18);
	}
	int u=next(q,k);
	cout<<u<<'\n';
	while(k>1){
		k--;
		u=next(G[u],k);
		cout<<u<<'\n';
	}
	return 0;
}

  

二.本题使用了CDQ分治,pre[i]为a[mid]~a[mid+i]中的最大值,sum数组为pre数组的前缀和数组,定义i和j,j每次枚举的是比a[i]大的值,根据这些来求解答案

39.此处求的是pre数组,根据pre数组的定义,所以选D

40.此处枚举了j,根据j的定义,故选B

41.此处使用max,求解max对答案的贡献,故选A

42.此处使用前缀和,求解pre数组的答案的贡献,故选C

43.此处的CDQ分治,使用的区间是左闭右开的,故选A

完整代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5+39+7;
int n,a[N];ll ans=0;
void solve(int l,int r){
	if(l+1==r){
		ans+=a[l];
		return;
	}
	int mid=(l+r)>>1;
	vector<int>pre(a+mid,a+r);
	for(int i=1;i<r-mid;i++)pre[i]=max(pre[i-1],pre[i]);
	vector<ll>sum(r-mid+1);
	for(int i=0;i<r-mid;i++)sum[i+1]=sum[i]+pre[i];
	for(int i=mid-1,j=mid,maxn=0;i>=l;i--){
		while(j<r&&a[j]<a[i])j++;
		maxn=max(maxn,a[i]);
		ans+=(ll)(j-mid)*maxn;
		ans+=(ll)(sum[r-mid]-sum[j-mid]);
	}
	solve(l,mid);
	solve(mid,r);
}
int main(){
	cin>>n;
	for(int i=0;i<n;i++)cin>>a[i];
	solve(0,n);
	cout<<ans;
	return 0;
}

  

posted @ 2023-09-18 22:37  天雷小兔  阅读(258)  评论(0)    收藏  举报