• 2017-2018 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2017)


    2017-2018 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2017)

    A: Airport Coffee

    一个人要从起点走到终点,距离为(d),速度恒(a)
    中间有一些咖啡馆,当经过咖啡馆买了咖啡后,速度会提高
    变成(b),具体点就是买了咖啡后持续(t)时间保持速度(a),之后
    持续(r)保持速度(b),最后速度又变回(a),每个咖啡馆最多只能买一杯咖啡,咖啡在中途可以扔掉再买新的,问从起点到终点的最短时间,输出在哪些咖啡馆买过咖啡,任意方案只要是最短时间即可。

    思路:

    定义(dp[i])表示从第(i)个咖啡馆出发买了咖啡到达终点的最短时间
    (dp[i] = min(dp[j] + cost(i,j)))
    暴力枚举复杂度为(O(n ^ {2}))
    注意到(dp[i] 从 1到 i) 一定是递减的
    且第(i)个点买了咖啡之后 可以分为三个阶段
    速度为 (a),速度为(b),速度再次为(a)
    第一个阶段和第三个阶段肯定选最接近(i)(j),第二个阶段肯定选最后的(j),所以其实只需要二分即可。

    #include<bits/stdc++.h>
    #define P pair<int,int>
    #define LL long long
    
    using namespace std;
    
    const LL INF = 1e18;
    const int N = 5e5 + 10;
    const double eps = 1e-10;
    LL d,a,b,t,r,n;
    LL cof[N];
    int nxt[N];
    double f[N];
    double cal(double x){
        if(x <= a * t) return x / a;
        if(x <= a * t + b * r) return t + (x - a * t)  / b;
        return t + r + (x - a * t - b * r) / a;
    }
    int main(){
    
       cin>>d>>a>>b>>t>>r;
       cin>>n;
       if(!n) {
        cout<<0<<endl;
        return 0;
       }
       for(int i = 0;i < n;i++){
            scanf("%lld",cof + i);
            f[i] = INF;
       }
       int flag = 0;
       if(cof[n - 1] != d) flag = 1,cof[n++] = d;
       else f[n - 1] = 0;
       nxt[n - 1] = -1;
       for(int i = n - 2;i >= 0;i--){
            int pos = lower_bound(cof, cof + n, cof[i]+1) - cof;
            if(cof[pos] - cof[i] - a * t < -eps){
                double tmp = f[pos] + cal(cof[pos] - cof[i]);
                if(tmp  - f[i]< -eps){
                    nxt[i] = pos,f[i] = tmp;
                }
            }
            pos = upper_bound(cof, cof + n, cof[i] + a * t + b * r) - cof;
            if(pos < n){
               double tmp = f[pos] + cal(cof[pos] - cof[i]);
                if(tmp - f[i] < -eps){
                    nxt[i] = pos,f[i] = tmp;
                }
            }
            if(a * t - cof[--pos] + cof[i] < -eps){
                double tmp = f[pos] + cal(cof[pos] - cof[i]);
                if(tmp - f[i] < -eps){
                    nxt[i] = pos,f[i] = tmp;
                }
            }
       }
       
       int u = 0;
       vector<int> res;
       while(u != -1){
            res.push_back(u);
            u = nxt[u];
       }
       if(*(res.end()-1) == n - 1 && flag) res.erase(res.end()-1);
       cout<<res.size()<<endl;
       if(res.size()){
        for(int i = 0 ;i < res.size();i++) cout<<res[i]<<" ";
        cout<<endl;
       }
       return 0;
    }
    

    C: Compass Card Sales

    在一个罗盘上给出(n)张卡片((r,g,b,id))
    (0 <= r,g,b < 360,0 <= id < 2^{31})
    定义卡片(i)(unique)分数为(x_l + x_r + y_l + y_r + z_l + z_r)
    (x_l)表示逆时针走最接近(r_i)(r)的差,(x_r)表示顺时针走最接近(r_i)(r)的差
    当有两个相同的(r_i)时,(x_l和x_r)等于0

    y和z同理

    (当卡片的unique分数相同时,id越大的越小)

    每次输出unique分数最小的卡片id,将它从罗盘上删去,然后更新其他卡片的分数,直到所有的卡片都删除。

    思路:

    丢到set中,每次删除一个卡片,最多只会对左右两边有影响,乱搞就好了,代码简直写的不能再乱了。

    #include<bits/stdc++.h>
    #define P pair<int,int>
    #define LL long long
    
    using namespace std;
    
    const int N = 1e5 + 10;
    struct node{
        int score,id;
        node(){};
        node(int score,int id):score(score),id(id){};
        bool operator<(const node &rhs)const{
            if(score != rhs.score) return score < rhs.score;
            return id > rhs.id;
        }
    
    };
    map<int,int> seq;
    set<node> se;
    int tmp[N];
    int ele[N][4];
    int vis[3][400];
    set<int> res[3][400];
    vector<int> angle[3];
    int l[3][400],r[3][400],sc[3][400];///逆时针,顺时针
    int calc_ang(int c,int x){
        if(vis[c][x] > 1) return 0;
        int ang = 0,ll = l[c][x],rr = r[c][x];
        ang += ll < x?x - ll:360 + x - ll;
        ang += rr > x?rr - x:360 + rr - x;
        return ang;
    }
    int cal(int x){
        int ans = 0;
        for(int i = 0;i < 3;i++) ans += sc[i][ele[x][i]];
        return ans;
    }
    void update(int x){
    
       for(int i = 0;i < 3;i++){
            int ang = ele[x][i];
            if(--vis[i][ang] == 0){
                int ll = l[i][ang],rr = r[i][ang];
                l[i][rr] = ll, r[i][ll] = rr;
                int tp = calc_ang(i,ll);
                if(sc[i][ll] != tp){
                    sc[i][ll] = tp;
                    for(auto v:res[i][ll]){
                        auto it = se.find(node(tmp[v],ele[v][3]));
                        se.erase(it);
                        tmp[v] = cal(v);
                        se.insert(node(tmp[v],ele[v][3]));
                    }
                }
                tp = calc_ang(i,rr);
                if(sc[i][rr] != tp){
                    sc[i][rr] = tp;
                    for(auto v:res[i][rr]){
                        auto it = se.find(node(tmp[v],ele[v][3]));
                        se.erase(it);
                        tmp[v] = cal(v);
                        se.insert(node(tmp[v],ele[v][3]));
                    }
                }
            }
            if(vis[i][ang] == 1){
                for(auto v:res[i][ang]){
                    sc[i][ang] = calc_ang(i,ang);
                    if(tmp[v] != cal(v)){
                        se.erase(se.find(node(tmp[v],ele[v][3])));
                        se.insert(node(tmp[v]=cal(v),ele[v][3]));
                    }
                }
            }
       }
    }
    int main(){
    
       int n;
       cin>>n;
       for(int i = 1;i <= n;i++){
            for(int j = 0;j < 4;j++) scanf("%d",&ele[i][j]);
            for(int j = 0;j < 3;j++) {
                    if(!vis[j][ele[i][j]]) angle[j].push_back(ele[i][j]);
                    res[j][ele[i][j]].insert(i);
                    vis[j][ele[i][j]]++;
            }
            seq[ele[i][3]] = i;
       }
       for(int i = 0;i < 3;i++){
            sort(angle[i].begin(),angle[i].end());
            for(int j = 0; j + 1 < angle[i].size();j++){
                l[i][angle[i][j + 1]] = angle[i][j];
                r[i][angle[i][j]] = angle[i][j+1];
            }
            l[i][angle[i][0]] = angle[i][angle[i].size() - 1];
            r[i][angle[i][angle[i].size() - 1]] = angle[i][0];
            for(int j = 0;j < angle[i].size();j++){
                sc[i][angle[i][j]] += calc_ang(i,angle[i][j]);
            }
       }
       for(int i = 1;i <= n;i++) {
            tmp[i] = cal(i);
            se.insert(node(tmp[i],ele[i][3]));
       }
       while(se.size() != 0){
            auto it = se.begin();
            int x = seq[it->id];
            printf("%d
    ",ele[x][3]);
            se.erase(it);
            for(int i = 0;i < 3;i++) res[i][ele[x][i]].erase(x);
            update(x);
       }
       return 0;
    }
    
    

    D: Distinctive Character

    题意:

    给出(n(n <= 10 ^{5}))长度为(k)的01串
    求出一个串使得与这(n)个串相似度的最大值最小
    相似度有多少位相同位相同

    思路:

    可以转化为成差异度的最小值最大。
    将这个(n)个串丢到队列中bfs,每次枚举不同的一位生成新的串,这样就知道了从(n)个串到该新串差异度的最小值,找出最大的那个串输出即可
    复杂度(O(20 * 2 ^ {20}))

    #include<bits/stdc++.h>
    #define P pair<int,int>
    #define LL long long
    
    using namespace std;
    
    const int N = (1<<20);
    int dis[N];
    queue<int> q;
    int main(){
    
       int n,k,s;
       cin>>n>>k;
       for(int i = 0;i < (1<<k);i++) dis[i] = -1;
       for(int i = 0;i < n;i++){
        string ss;
        s = 0;
        cin>>ss;
        for(int j = 0;j  < k;j++){
            if(ss[j] == '1') s += (1<<j);
        }
        q.push(s);
        dis[s] = 0;
       }
       int ans = 0,mx = 0;
       while(!q.empty()){
        int u = q.front();q.pop();
        for(int i = 0;i < k;i++){
            int v = u ^ (1<<i);
            if(dis[v] != -1) continue;
            dis[v] = dis[u] + 1;
            q.push(v);
            if(mx < dis[v]){
                mx = dis[v];
                ans = v;
            }
        }
       }
       for(int i = 0;i < k;i++) printf("%d", (ans & (1<<i)?1:0));
       printf("
    ");
       return 0;
    }
    

    K: Kayaking Trip

    思路:二分一个答案(v),那么对于所有的(frac{v}{c_i})
    对于所有的(s_n,s_b,s_e)
    能够找到(frac{n+b+e}{2})的对数
    每一对对应满足(s_{i1}+s_{i2}) >= (frac{v}{c_i})
    贪心的去选来判断是否满足即可
    复杂度(O(n log n))

    #include<bits/stdc++.h>
    #define P pair<int,int>
    #define LL long long
    
    using namespace std;
    
    const int N = 1e5 + 10;
    int a[3],b[3],n;
    int c[N];
    bool is(int mid){
        int x = a[0],y = a[1],z = a[2];
        for(int i = n / 2 - 1;i >= 0;i--){
            int p = mid / c[i] + (mid % c[i]?1:0);
            if(x >= 2 && 2* b[0] >= p) {
                x -= 2;
            }
            else if(x && y && b[0] + b[1] >= p){
                x--,y--;
            }else if(y >= 2 && 2 * b[1] >= p){
                if(x && z && b[0] + b[2] >= p && 2 * b[1] > b[0] + b[2]){
                    x--,z--;
                }else {
                    y -= 2;
                }
            }else if(x && z && b[0] + b[2] >= p){
              x--,z--;
            }else if(y && z && b[1] + b[2] >= p){
                    y--,z--;
            }else if(z >= 2 && 2 * b[2] >= p){
                z -= 2;
            }
            else return false;
        }
        return true;
    }
    int main(){
    
       for(int i = 0;i < 3;i++) cin>>a[i];
       for(int i = 0;i < 3;i++) cin>>b[i];
       n = a[0] + a[1] + a[2];
       for(int i = 0;i < n / 2;i++) cin>>c[i];
       sort(c,c + n / 2);
       int L = 0,R = 100000 * 2000,ans = 0;
       while(L <= R){
        int mid = L + R >> 1;
        if(is(mid)) ans = max(ans,mid),L = mid + 1;
        else R = mid - 1;
       }
       cout<<ans<<endl;
       return 0;
    }
    
  • 相关阅读:
    安装 oracle
    svn 编辑
    软件构架
    liunx操作
    css的样式分类
    简单自己做了一个个人简历
    网页制作之表格,列表
    MYSQL表创建
    linux操作指令 第二部分
    linux操作指令 第一部分
  • 原文地址:https://www.cnblogs.com/jiachinzhao/p/7768913.html
Copyright © 2020-2023  润新知