省选模拟3.22
$T1$
考场上分析出了几个性质,觉得是个贪心$/DP$结果从贪心耽误太久了,$dp$没有细想
还是说$dp[i]$表示前$i$个子图的满足情况的最小价值
怎么说,考场上想到的那个贪心就是这个,然后我对于区间操作就卡了,好吧,我还是稍逊一些
还是说,我们转移的时候,先看一下,我们这一段的右端点在哪
那么就可以分块转移了
其实只有两种转移吧,一个是后面直接连前面,或者目前点直接连最远点
目前点到最远点之间会存在断点使得使得两边断掉,那么还是一个个转移就好了
在思考一下
其实本质过程是分段,$n^3$的话很好说
我们考虑优化掉一维$dp[i]$表示前$i$个分成若干段代价的最小值,考虑$i->j$
那么就很好说了
首先我们对于这一部分,我们现在是$l$,我们对于我们目前可达右端点,必然是枚举当前是否为断点去判断
我们往后更新的话,需要更新一下连边情况,如果当前点,没有被打标记,其余的区间赋值,没有连边的都连上就好了,或者更新下一步能不能断点就好了,挺神的
#include<cstring> #include<vector> #include<cstdio> using namespace std; int n,m,in1,in2,dp[200010]; vector<int>ed[200010];bool vis[200010]; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d%d",&in1,&in2); ed[min(in1,in2)].push_back(max(in1,in2)); } memset(dp,0x3f,sizeof(dp)); dp[1]=0; for(int l=1,r=1,cn=0;l<=n;l++) { if(!vis[l])cn++; for(vector<int>::iterator ite=ed[l].begin();ite!=ed[l].end();ite++) { r=max(r,*ite); if(!vis[*ite]) cn++,vis[*ite]=true; } r=max(r,l+1); dp[r]=min(dp[r],dp[l]+r-cn); if(l!=1)dp[l+1]=min(dp[l+1],dp[l]+1); } printf("%d",dp[n]);return 0; }
$T2$
考场上想到了前两步,$1,2$起手,然后不会往后延伸了
只有$HH$和我一样...
那么以示尊敬,$1,2$起手
然后对于后面来说,我们对于目前点都能到的点都连$100$
最优解的话,我们保证都有一条向上的$1$
跑出来的是这样走$1->2->3->5/1->4->6$
最优解的话可以$1->2->4->5->8->9/1->3->6->7$
就是隔一个跨三个,然后一个连后面
大概就是走一步走三步这样就好了
$T3$
上午最短路写成大根堆了$QAQ$
//没处理向下的 //用脑子想一想 //出现问题的只有前面一部分,如果那么只需要H和dis取个max就好了 //其实也就是,前面的dis如果不大于H,证明前面这部分还有剩余 //其实就是看这个影响的部分,首先我们不需考虑往上的代价,只需要考虑往下和前进的代价的代价 //如果我们前面的距离不足到的话,我们就需要取个max //dis的两种更新方式罢了 #include<bits/stdc++.h> #define INF 0x3f3f3f3f3f3f3f3f #define int long long #define MAXN 6000005 using namespace std; int head[MAXN],nxt[MAXN],val[MAXN],dis[MAXN],to[MAXN],h[MAXN],tot,H,n,m; priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >q; bool vis[MAXN]; void add(int u,int v,int w) { tot++; to[tot]=v; val[tot]=w; nxt[tot]=head[u]; head[u]=tot; } void dij() { memset(dis,0x3f,sizeof(dis)); dis[1]=0; q.push(make_pair(dis[1],1)); while(!q.empty()) { int now=q.top().second; q.pop(); if(vis[now]) continue; vis[now]=true; for(int i=head[now];i;i=nxt[i]) { int y=to[i]; int w=dis[now]+val[i]; if(H>h[y]) w=max(w,H-h[y]); if(dis[y]>w) { dis[y]=w; q.push(make_pair(dis[y],y)); } } } if(dis[n]==INF) { puts("-1"); exit(0); } cout<<2*dis[n]-H+h[n]; } int u,v,w; signed main() { cin>>n>>m>>H; for(int i=1;i<=n;i++) { cin>>h[i]; } for(int i=1;i<=m;i++) { cin>>u>>v>>w; if(h[u]>=w) add(u,v,w); if(h[v]>=w) add(v,u,w); } dij(); }