2019杭电多校第一场

11 篇文章 0 订阅
4 篇文章 0 订阅

1004 Vacation

二分最终时间,然后从第一辆车开始递推求出每辆车的最终位置。复杂度为 O ( n log ⁡ C ) O(n\log C) O(nlogC)

STD::把第 i i i辆车追上第 i + 1 i+1 i+1辆车当作一个事件,显然只有 n n n个事件,且第 i i i辆车追上第 i + 1 i+1 i+1辆车只可能会对第 i − 1 i-1 i1辆车追上第 i i i辆车的时间产生影响,且时间一定是变小,因此可以维护车之间的距离和速度来计算事件发生时间,用堆来找出最早发生的事件,不停处理直到 0 0 0车通过停车线。复杂度为 O ( n log ⁡ n ) O(n\log n) O(nlogn)

UPD 发现有很多大佬写了 O ( n ) O(n) O(n)的做法,大概是这样:最终通过停止线的时候,一定是一个车后面堵着剩余所有的车,那么影响时间的就只有最前面这辆车,所以对于每一辆车,假设是它是和 0 0 0车堵在一起的最靠前的一辆车,那么可以计算出一个值,所有的车的计算值的最大值就是答案。

#include<bits/stdc++.h>
#define ll long long
#define Max(a,b) ((a) > (b) ? (a) : (b))
#define INF 0x3f3f3f3f
const int mod = 1e9+7;
const int maxn = 1e5 + 10 ;
typedef std::pair<int, int> pii;
typedef std::pair<ll, ll> pll;
ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}
using namespace std;
int n,l[maxn],s[maxn],v[maxn];
double pos[maxn];
int check(double t){
    pos[n]=s[n]-v[n]*t;
    for(int i=n-1;i>=0;i--){
        double x=v[i]*t;
        pos[i]=s[i]-x;
        if(pos[i]<pos[i+1]+l[i+1]) pos[i]=pos[i+1]+l[i+1];
    }
    return pos[0]<0;
}
int main() {
    ios_base::sync_with_stdio(false);cin.tie(0);
    while(cin>>n)
    {
        for (int i=0;i<=n;i++) scanf("%d",&l[i]);
        for (int i=0;i<=n;i++) scanf("%d",&s[i]);
        for (int i=0;i<=n;i++) scanf("%d",&v[i]);
        double L=0,R=1e9,mid;
        while(R-L>1e-6)
        {
            mid = (L+R)/2;
            if (check(mid)) R=mid;
            else L=mid;
        }
        cout<<fixed<<setprecision(10)<<mid<<endl;
    }
    return 0;
}

1005 Path

给一个图,删去一条边的代价为边权,用最小的代价和使最短路增加。
solutiion:跑一遍最短路,然后用d[e.v] - d[u] = e.w的边建图,求最小割。

#include<bits/stdc++.h>
#define ll long long
#define Max(a,b) ((a) > (b) ? (a) : (b))
const long long INF=1e18;
const int mod = 1e9+7;
const int maxn = 1e5 + 10 ;
typedef std::pair<int, int> pii;
typedef std::pair<ll, ll> pll;
ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}
using namespace std;
int vis[maxn],m,n;
ll d[maxn];
class Graph
{
private:
    int s,t;
    int Head[maxn];
    int Next[maxn];
    ll cnt;
    ll V[maxn];
    ll W[maxn];
    ll Depth[maxn];
public:
    void init(int nn,int ss,int tt)//初始化
    {
        n=nn;
        s=ss;
        t=tt;
        cnt=-1;
        memset(Head,-1,sizeof(Head));
        memset(Next,-1,sizeof(Next));
        return;
    }
    void _Add(int u,int v,ll w)
    {
        ++cnt;
        Next[cnt]=Head[u];
        V[cnt]=v;
        W[cnt]=w;
        Head[u]=cnt;
    }
    void Add_Edge(int u,int v,ll w)//加边,同时加正向和反向的
    {
        _Add(u,v,w);
        _Add(v,u,0);
    }
    ll dfs(int u,ll dist)
    {
        //cout<<"Dfs:"<<u<<' '<<dist<<endl;
        if (u==t)
            return dist;
        for (int i=Head[u];i!=-1;i=Next[i])
        {
            if ((Depth[V[i]]==Depth[u]+1)&&(W[i]!=0))
            {
                ll di=dfs(V[i],min(dist,W[i]));
                if (di>0)
                {
                    W[i]-=di;
                    W[i^1]+=di;
                    return di;
                }
            }
        }
        return 0;
    }
    int bfs()
    {
        //cout<<"Bfs.begin:"<<endl;
        queue<ll> Q;
        while (!Q.empty())
            Q.pop();
        memset(Depth,0,sizeof(Depth));
        Depth[s]=1;
        Q.push(s);
        do
        {
            int u=Q.front();
            //cout<<"u:"<<u<<endl;
            Q.pop();
            for (int i=Head[u];i!=-1;i=Next[i])
            {
                if ((W[i]>0)&&(Depth[V[i]]==0))
                {
                    Depth[V[i]]=Depth[u]+1;
                    Q.push(V[i]);
                }
            }
        }
        while (!Q.empty());
        //cout<<"Bfs.end"<<endl;
        if (Depth[t]>0)
            return 1;
        return 0;
    }
    ll Dinic()
    {
        ll Ans=0;
        while (bfs())
        {
            while (ll d=dfs(s,INF))
                Ans+=d;
        }
        return Ans;
    }
};
struct node{
    int v;
    ll w;
    node(int v=0,ll w=0):v(v),w(w){};
    bool operator <(const node &rhs)const{
        return w>rhs.w;
    }
};
vector<node> G[maxn];
void init(){
    cin>>n>>m;
    for (int i = 1; i<=1e4; i++) {
        G[i].clear();
        d[i] = INF;
    }
    memset(vis,0,sizeof vis);
    int x,y;ll z;
    for(int i=1;i<=m;i++) {
        cin>>x>>y>>z;
        G[x].push_back(node(y, z));
        //G[y].push_back((node){x, z});
    }
}
void dijkstra(){
    priority_queue<node> q;
    q.push(node(1,0));
    d[1]=0;
    while(!q.empty())
    {
        node top=q.top();q.pop();
        int u = top.v;
        if (vis[u]) continue;
        vis[u]=1;
        for(int i=0;i<G[u].size();i++){
            node v=G[u][i];
            if (d[v.v] > d[u] + v.w) {
                d[v.v] = d[u] + v.w;
                q.push(node(v.v, d[v.v]));
            }
        }
    }
}
int main() {
    //freopen("/Users/cumt27/Desktop/02.in.txt","r",stdin);
    ios_base::sync_with_stdio(false);cin.tie(0);
    int iCase;
    cin >> iCase;
    while(iCase--) {
        init();
        dijkstra();
        if (d[n] == INF)
            std::cout << "0\n";
        else {
            Graph gu;
            gu.init(n,1,n);
            for (int u = 1; u <= n; u++)
                for (auto e : G[u])
                    if (d[e.v] - d[u] == e.w)
                        gu.Add_Edge(u, e.v, e.w);
            std::cout << gu.Dinic() << '\n';
        }
    }
    return 0;
}

1009 String

n x t [ i ] [ j ] nxt[i][j] nxt[i][j]表示i位置之后第一次出现j的位置.
对于每一个位置,贪心的从 a a a z z z枚举当前可填字母,如果满足条件,立刻填上该字母,然后填下一个位置。

#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<string.h>
#include<iostream>
#include<algorithm>
#define ll long long
#define Max(a,b) ((a) > (b) ? (a) : (b))
const long long INF=1e18;
const int mod = 1e9+7;
const int maxn = 1e5 + 10 ;
typedef std::pair<int, int> pii;
typedef std::pair<ll, ll> pll;
ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}
using namespace std;
int used[26], l[26], r[26];
int cnt[maxn][26], nxt[maxn][26];
int n, k;
char s[maxn], ans[maxn];
inline void init(){
    n=strlen(s);
    for(int i=0;i<26;i++)
        cin>>l[i]>>r[i];
    memset(cnt,0,sizeof cnt);
    memset(nxt,0,sizeof nxt);
    memset(used,0,sizeof used);
    for(int i=n-1;i>=0;i--) {
        for (int j = 0; j < 26; j++) {
            nxt[i][j] = nxt[i + 1][j];
            cnt[i][j] = cnt[i + 1][j] + (s[i] == 'a' + j);
        }
        nxt[i][s[i]-'a']=i;
    }
}
int main() {
    //freopen("/Users/cumt27/Desktop/02.in","r",stdin);
    ios_base::sync_with_stdio(false);cin.tie(0);
    while(cin>>s>>k){
        init();
        int last=-1;
        for(int i = 0;i < k; i++){
            int find=0;
            for(int j = 0;j < 26; j++)
                if(used[j]<r[j])
                {
                    ++used[j];
                    int flag=1,sum=0,pos=nxt[last+1][j];
                    if(pos<last) continue;//在这里wa了无数次,当遍历完这个字母时,nxt会跳回去
                    for(int p=0;p<26;p++){
                        if(cnt[pos+1][p] + used[p] < l[p]) flag=0;//剩下的无法满足左边界
                        sum+=max(l[p] - used[p],0);//剩下的必须要填的字母
                    }
                    if(sum > k-i-1) flag=0;
                    sum=0;
                    for(int p=0;p<26;p++)
                        sum+=min(cnt[pos+1][p],r[p]-used[p]);//剩下的能填的字母
                    if(sum < k-i-1) flag=0;
                    if (!flag) --used[j];
                    else {
                        ans[i] = 'a' + j;
                        find = 1;
                        last = pos;
                        break;
                    }
                }
            if(!find) {
                printf("-1\n");
                goto end;
            }
        }
        ans[k]='\0';
        printf("%s\n",ans);
        end:;
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值