2019杭電多校第一場

1004 Vacation

二分最終時間,然後從第一輛車開始遞推求出每輛車的最終位置。複雜度爲O(nlogC)O(n\log C)

STD::把第ii輛車追上第i+1i+1輛車當作一個事件,顯然只有nn個事件,且第ii輛車追上第i+1i+1輛車只可能會對第i1i-1輛車追上第ii輛車的時間產生影響,且時間一定是變小,因此可以維護車之間的距離和速度來計算事件發生時間,用堆來找出最早發生的事件,不停處理直到00車通過停車線。複雜度爲O(nlogn)O(n\log n)

UPD 發現有很多大佬寫了O(n)O(n)的做法,大概是這樣:最終通過停止線的時候,一定是一個車後面堵着剩餘所有的車,那麼影響時間的就只有最前面這輛車,所以對於每一輛車,假設是它是和00車堵在一起的最靠前的一輛車,那麼可以計算出一個值,所有的車的計算值的最大值就是答案。

#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

nxt[i][j]nxt[i][j]表示i位置之後第一次出現j的位置.
對於每一個位置,貪心的從aazz枚舉當前可填字母,如果滿足條件,立刻填上該字母,然後填下一個位置。

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章