标签:last min its 技术 超过 杭电 速度 path 删掉
题解:题目给出两个人要去旅行,在他们前面有n辆车,每辆车有长度以及车首部到stopline 的距离以及每辆车的最大速度,后面的车不能超过前面的车。问你他们两个的车首部到达stopline的最短时间。
思路:二分答案,求出最后一辆车停在的位置。
参考代码:
#include<bits/stdc++.h> using namespace std; #define mkp make_pair<int,int> typedef long long ll; const int maxn=2e5+10; double eps=1e-12; ll n; struct Node{ ll l,s,v; } a[maxn]; int check(double x) { double ans=a[n].s-a[n].v*x; for(int i=n-1;i>=0;i--) { if(a[i].s-a[i].v*x<=ans+a[i+1].l) ans+=a[i+1].l; else ans=a[i].s-a[i].v*x; } return ans<=eps; } int main() { while(~scanf("%lld",&n)) { for(int i=0;i<=n;i++) scanf("%lld",&a[i].l); for(int i=0;i<=n;i++) scanf("%lld",&a[i].s); for(int i=0;i<=n;i++) scanf("%lld",&a[i].v); double l=0,r=1e18; while(r-l>eps) { double mid=(l+r)/2; if(check(mid)) r=mid; else l=mid; } printf("%.10f\n",r); } return 0; }
题解:给你n个点,m条边(有向边),每天变有一定的权值。让你求删掉一些边使得1到 n 的最短路径变大的最小代价(代价是删除的边的边权之和)。
思路:先跑一遍最短路求出1到其他点的最短距离,然后 倒着dfs 求出最短路的DAG的所有边,重新建图,跑最小割就行了。
参考代码:
#include<bits/stdc++.h>///////// #define int long long #define ll long long #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; const int MAXN = 10010; const int INF=0x3f3f3f3f3f3f3f3fll; struct node{ int to; int val; int next; }edge[MAXN*100*2],e[MAXN*200*5]; int ind,pre[MAXN],vis[MAXN],dis[MAXN],pre1[MAXN],ind1; int now[MAXN],S,T; int n,m; void add1(int x,int y,int z) { e[ind1].to = y; e[ind1].val = z; e[ind1].next = pre1[x]; pre1[x] = ind1 ++; } void spfa() { for(int i = 1; i <= n; i++){ dis[i] = INF; vis[i] = 0; } vis[T] = 1; dis[T] = 0; queue<int>q; q.push(T); while(!q.empty()){ int tp = q.front(); q.pop(); vis[tp] = 0; for(int i = pre1[tp]; i != -1; i = e[i].next){ int t = e[i].to; if(dis[t] > dis[tp] + e[i].val){ dis[t] = dis[tp] + e[i].val; if(!vis[t]){ vis[t] = 1; q.push(t); } } } } } void add(int x,int y,int z) { edge[ind].to = y; edge[ind].val = z; edge[ind].next = pre[x]; pre[x] = ind ++; } void dfs1(int rt) { vis[rt] = 1; if(rt == T)return ; for(int i = pre1[rt]; i != -1; i = e[i].next){ int t = e[i].to; if(now[rt] + dis[t] + e[i].val == dis[S]){ now[t] = now[rt] + e[i].val; add(rt,t,e[i].val); add(t,rt,0); if(!vis[t]){ dfs1(t); } } } } int bfs() { memset(vis,-1,sizeof(vis)); queue<int>q; vis[S] = 0; q.push(S); while(!q.empty()){ int tp = q.front(); q.pop(); for(int i = pre[tp]; i != -1; i = edge[i].next){ int t = edge[i].to; if(vis[t] == -1 && edge[i].val){ vis[t] = vis[tp] + 1; q.push(t); } } } if(vis[T] == -1)return 0; return 1; } int dfs(int rt,int low) { int used = 0; if(rt == T)return low; for(int i = pre[rt]; i != -1 && used < low; i = edge[i].next){ int t = edge[i].to; if(vis[t] == vis[rt] + 1 && edge[i].val){ int a = dfs(t,min(low-used,edge[i].val)); used += a; edge[i].val -= a; edge[i^1].val += a; } } if(used == 0)vis[rt] = -1; return used; } int x[MAXN*100],y[MAXN*100],z[MAXN*100]; void Init(int flag) { ind1 = 0; memset(pre1,-1,sizeof(pre1)); for(int i = 1; i <= m; i++){ if(!flag){ add1(y[i],x[i],z[i]); } else { add1(x[i],y[i],z[i]); } } } int32_t main() { int t; scanf("%lld",&t); while(t--){ scanf("%lld%lld",&n,&m); for(int i = 1; i <= m; i++){ scanf("%lld%lld%lld",&x[i],&y[i],&z[i]); } Init(0); S=1,T=n; spfa(); Init(1); ind = 0; memset(now,0,sizeof(now)); memset(pre,-1,sizeof(pre)); dfs1(S); int ans = 0; while(bfs()) { while(1) { int a = dfs(S,INF); if(!a)break; ans += a; } } printf("%lld\n",ans); } return 0; }
题解:题目意思是给你一个长度为N的字符串,然后给你一个K,让你求满足条件的字典序最小的长度为K的子序列。
对于子序列的要求为:(Li,Ri):表示子序列中对应字符的数量应该在这个区间之间
参考代码:
#include <bits/stdc++.h> using namespace std; const int N=2e5+7; char s[N],ans[N]; int k,n,cnt[N][26],l[26],r[26],used[26],last; vector<int> vec[26]; int main() { while(~scanf("%s%d",s,&k)) { for(int i=0;i<=25;++i) scanf("%d%d",l+i,r+i); n = strlen(s); memset(used,0,sizeof(used)); memset(cnt[n],0,sizeof(cnt[n])); for(int i=0;i<26;++i) vec[i].clear(); for(int i=n-1;i>=0;--i) for(int j=0;j<=25;++j) cnt[i][j]=cnt[i+1][j]+(s[i]==‘a‘+j); for(int i=0;i<=n-1;++i) vec[s[i]-‘a‘].push_back(i); vector<int>::iterator head[26]; for(int i=0;i<=25;++i) head[i]=vec[i].begin(); last=-1; bool temp=true; for(int i=0;i<=k-1;++i) { bool f1=0; for(int j=0;j<=25;++j) { if(used[j]==r[j]) continue; while(head[j]!=vec[j].end() && (*head[j])<=last) head[j]++; if(head[j]==vec[j].end()) continue; used[j]++;//加上这个位置字符 bool flag=1; int pos=(*head[j]),sum=0; //判断已经使用的数量加上后面的剩余的数量是否满足题意 for(int t=0;t<=25;++t) { if(cnt[pos+1][t]+used[t]<l[t]) flag=0; sum+=max(l[t]-used[t],0); } if(sum>k-i-1) flag=0; sum=0; //最多能使用的字符数量 for(int t=0;t<=25;++t) sum+=min(cnt[pos+1][t],r[t]-used[t]); if(sum<k-i-1) flag=0; if(!flag) used[j]--; else { ans[i]=‘a‘+j; f1=1; last=pos; break; } } if(!f1) { puts("-1");temp=false;break;} } if(!temp) continue; ans[k]=‘\0‘; printf("%s\n",ans); } return 0; }
后面的题解慢慢更新~
标签:last min its 技术 超过 杭电 速度 path 删掉
原文地址:https://www.cnblogs.com/songorz/p/11229659.html