码迷,mamicode.com
首页 > 其他好文 > 详细

2019 杭电多校第一场

时间:2019-07-23 09:52:09      阅读:143      评论:0      收藏:0      [点我收藏+]

标签:last   min   its   技术   超过   杭电   速度   path   删掉   

D Vacation

题解:题目给出两个人要去旅行,在他们前面有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;
}
View Code

E Path

题解:给你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;
}
View Code

I String

题解:题目意思是给你一个长度为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;
}
View Code

 

后面的题解慢慢更新~

 

2019 杭电多校第一场

标签:last   min   its   技术   超过   杭电   速度   path   删掉   

原文地址:https://www.cnblogs.com/songorz/p/11229659.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!