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;
}

浙公网安备 33010602011771号