暑假集训CSP提高模拟11
组题人: @KafuuChinocpp
\(T1\) P152. Fate \(24pts\)
-
强化版: HDU1688 Sightseeing
-
设 \(dis_{i,0/1}\) 表示从 \(s\) 到 \(i\) 的最短路/次短路长度, \(f_{i,0/1}\) 表示从 \(s\) 到 \(i\) 的最短路/次短路条数。
-
\(dijkstra\) 过程中按照路径长度与最短路、次短路的大小关系四种情况进行反讨。
-
由于需要统计最短路及次短路,
vis
数组同样需要记录当前是最短路还是次短路去更新状态 -
最后判断一下次短路长度是否等于最短路长度减一。
点击查看代码
const ll p=1000000007; struct node { ll nxt,to,w; }e[400010]; struct quality { ll dis,x,id; bool operator < (const quality another) const { return dis>another.dis; } }; ll head[400010],vis[400010][2],dis[400010][2],f[400010][2],cnt=0; void add(ll u,ll v,ll w) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; e[cnt].w=w; head[u]=cnt; } void dijkstra(ll s) { ll x,id,i; priority_queue<quality>q; memset(dis,0x3f,sizeof(dis)); memset(vis,0,sizeof(vis)); dis[s][0]=0; f[s][0]=1; q.push((quality){dis[s][0],s,0}); while(q.empty()==0) { x=q.top().x; id=q.top().id; q.pop(); if(vis[x][id]==0) { vis[x][id]=1; for(i=head[x];i!=0;i=e[i].nxt) { if(dis[e[i].to][0]>dis[x][id]+e[i].w) { dis[e[i].to][1]=dis[e[i].to][0]; f[e[i].to][1]=f[e[i].to][0]; dis[e[i].to][0]=dis[x][id]+e[i].w; f[e[i].to][0]=f[x][id]; q.push((quality){dis[e[i].to][0],e[i].to,0}); q.push((quality){dis[e[i].to][1],e[i].to,1}); } else { if(dis[e[i].to][0]==dis[x][id]+e[i].w) { f[e[i].to][0]=(f[e[i].to][0]+f[x][id])%p; } else { if(dis[e[i].to][1]>dis[x][id]+e[i].w) { dis[e[i].to][1]=dis[x][id]+e[i].w; f[e[i].to][1]=f[x][id]; q.push((quality){dis[e[i].to][1],e[i].to,1}); } else { if(dis[e[i].to][1]==dis[x][id]+e[i].w) { f[e[i].to][1]=(f[e[i].to][1]+f[x][id])%p; } } } } } } } } int main() { ll n,m,s,t,u,v,i; cin>>n>>m>>s>>t; for(i=1;i<=m;i++) { cin>>u>>v; add(u,v,1); add(v,u,1); } dijkstra(s); cout<<(dis[t][1]-1==dis[t][0])*f[t][1]<<endl; return 0; }
\(T2\) P153. EVA \(5pts\)
-
从贪心的角度分析,网的一端和至少一条鱼重合一定不劣。
-
考虑枚举与左端点重合的鱼,然后固定这条鱼,令其他鱼与其做相对运动,处理出进入网的左右 \(t\) 边界,差分后,由于左端点已经固定,所以直接继承即可。
-
特判速度相等的情况。
-
略卡精度。
点击查看代码
const double eps=1e-10; int w[2010],x[2010],v[2010]; map<double,int>d; map<double,int>::iterator it; int main() { int n,a,ans=0,sum,i,j; double l,r; cin>>n>>a; for(i=1;i<=n;i++) { cin>>w[i]>>x[i]>>v[i]; } for(i=1;i<=n;i++) { d.clear(); sum=w[i]; for(j=1;j<=n;j++) { if(i!=j) { if(v[i]==v[j]) { if(x[i]<=x[j]&&x[j]<=x[i]+a) { sum+=w[j]; } } else { l=1.0*(x[i]-x[j])/(v[j]-v[i]); r=1.0*(x[i]+a-x[j])/(v[j]-v[i]); if(l-r>eps)//左右端点颠倒了要颠倒回来 { swap(l,r); } if(r>=0)//保证存在区间 { l=max(l,0.0); d[l]+=w[j]; d[r+eps]-=w[j]; } } } } ans=max(ans,sum); for(it=d.begin();it!=d.end();it++) { sum+=it->second; ans=max(ans,sum); } } cout<<ans<<endl; return 0; }
\(T3\) P166. 嘉然登场 \(5pts\)
- 原题: [ARC148E] ≥ K
\(T4\) P178. Clannad \(0pts\)
总结
- \(T1\)
- 没想到在 \(dijkstra\) 过程中同样也能更新次短路,说明对 \(dijkstra\) 节点标记的认识不清楚。
- 在最短路 \(DAG\) 上统计答案上仅考虑到了最短路径上的点,没考虑到非最短路径上的点也能转移过来。
后记
-
奖励的限制越来越苛刻了。
-
题目背景夹带私货。