• Codeforces Round #222 (Div. 1) (ABCDE)


    377A Maze

    大意: 给定棋盘, 保证初始所有白格连通, 求将$k$个白格变为黑格, 使得白格仍然连通.

    $dfs$回溯时删除即可. 

    #include <iostream>
    #include <functional>
    #include <sstream>
    #include <algorithm>
    #include <cstdio>
    #include <math.h>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <string.h>
    #include <bitset>
    #define REP(i,a,n) for(int i=a;i<=n;++i)
    #define PER(i,a,n) for(int i=n;i>=a;--i)
    #define hr putchar(10)
    #define pb push_back
    #define lc (o<<1)
    #define rc (lc|1)
    #define mid ((l+r)>>1)
    #define ls lc,l,mid
    #define rs rc,mid+1,r
    #define x first
    #define y second
    #define io std::ios::sync_with_stdio(false)
    #define endl '
    '
    #define DB(a) ({REP(__i,1,n) cout<<a[__i]<<' ';hr;})
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int P = 1e9+7, INF = 0x3f3f3f3f;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
    ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
    inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
    //head
    
    
    
    const int N = 1e3+10;
    int n,m,s,px,py;
    int vis[N][N];
    char a[N][N];
    const int dx[]={0,0,-1,1};
    const int dy[]={-1,1,0,0};
    
    int main() {
        scanf("%d%d%d", &n, &m, &s);
        REP(i,1,n) cin>>a[i]+1;
        REP(i,1,n) REP(j,1,m) if (a[i][j]=='.') px=i,py=j;
        function<void(int,int)> dfs = [&](int x, int y) {
            if (x<=0||y<=0||x>n||y>m||vis[x][y]||a[x][y]=='#') return;
            vis[x][y] = 1;
            REP(k,0,3) dfs(x+dx[k],y+dy[k]);
            if (s) --s,a[x][y]='X';
        };
        dfs(px,py);
        REP(i,1,n) puts(a[i]+1);
    }
    View Code

    377B Preparing for the Contest 

    大意: $m$道题, $n$个学生, 每个学生每天做一道题, 每个学生只能做难度不超过他的能力的题, 雇第$i$个学生做题需要花费$j$元, 求最短时间做完所有题的情况下的最少花费, 输出方案.

    二分答案, 维护一个堆贪心

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <queue>
    #include <functional>
    #define x first
    #define y second
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
    
    int main() {
        int n=rd(),m=rd(),s=rd();
        vector<pii> f(m);
        int id = 0;
        for(auto &t:f) t.x=rd(),t.y=id++;
        sort(begin(f),end(f),greater<pii>());
        vector<pair<int,pii> > g(n);
        id = 0;
        for(auto &t:g) t.x=rd();
        for(auto &t:g) t.y.x=rd(),t.y.y=++id;
        sort(begin(g),end(g),greater<pair<int,pii>>());
        vector<int> ans(m);
        auto chk = [&](int x) {
            auto now = g.begin();
            auto pos = f.begin();
            int sum = 0;
            priority_queue<pii,vector<pii>,greater<pii>> q;
            while (pos!=f.end()) {
                while (now!=g.end()&&now->x>=pos->x) q.push((now++)->y);
                if (q.empty()) return 0;
                auto mi = q.top(); q.pop();
                if (!mi.y||sum+mi.x>s) return 0;
                sum += mi.x;
                int t = x;
                while (pos!=f.end()&&t--) ans[(pos++)->y]=mi.y;
            }
            return 1;
        };
        int l=1,r=m,ret=-1;
        while (l<=r) {
            int mid = (l+r)/2;
            if (chk(mid)) ret=mid,r=mid-1;
            else l=mid+1;
        }
        if (ret==-1) return cout<<"NO"<<endl,0;
        cout<<"YES"<<endl;
        chk(ret);
        for (auto &t:ans) cout<<t<<' ';
        cout<<endl;
    }
    View Code

    377C Captains Mode

    大意: $n$个英雄, 给出两个队伍的操作序列, 操作$(p,x)$表示第$x$队选一个英雄, 操作$(b,x)$表示第$x$队禁一个英雄. 一个英雄被选过或被禁过就不能再选, 禁英雄操作可以跳过. 第一个队想要最大化两个队英雄属性和的差, 第二个队想要最小化. 求最优情况下的差值.

    只需考虑属性前$m$大的英雄即可, 那么很容易有$O(m^22^m)$的$dp$

    但是可以注意到禁英雄一定会比不禁英雄更优, 那么每个阶段可用英雄数是固定的, 所以第$i$个阶段状态数是$inom{m}{m-i}$, 这样复杂度可以达到$O(m2^m)$.

    #include <iostream>
    #include <sstream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <cstring>
    #include <bitset>
    #include <functional>
    #include <random>
    #define REP(i,a,n) for(int i=a;i<=n;++i)
    #define PER(i,a,n) for(int i=n;i>=a;--i)
    #define hr putchar(10)
    #define pb push_back
    #define lc (o<<1)
    #define rc (lc|1)
    #define mid ((l+r)>>1)
    #define ls lc,l,mid
    #define rs rc,mid+1,r
    #define x first
    #define y second
    #define io std::ios::sync_with_stdio(false)
    #define endl '
    '
    #define DB(a) ({REP(__i,1,n) cout<<a[__i]<<' ';hr;})
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int P = 1e9+7, INF = 0x3f3f3f3f;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
    ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
    inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
    //head
    
    
    
    const int N = 2e6+10;
    int n, m, a[N], f[N];
    int dp[N];
    
    void chkmin(int &a, int b) {a>b?a=b:0;}
    void chkmax(int &a, int b) {a<b?a=b:0;}
    int main() {
        scanf("%d", &n);
        REP(i,0,n-1) scanf("%d",a+i);
        scanf("%d", &m);
        sort(a,a+n,greater<int>());
        REP(i,0,m-1) { 
            char op;
            int x;
            scanf(" %c%d", &op, &x);
            f[i] = (op=='p')<<1|(x==1);
        }
        int mx = (1<<m)-1;
        REP(S,1,mx) {
            int i = m-__builtin_popcount(S);
            int &r = dp[S];
            if (f[i]==0) {
                r = INF;
                REP(j,0,m-1) if (S>>j&1) {
                    chkmin(r,dp[S^1<<j]);
                }
            }
            else if (f[i]==1) {
                r = -INF;
                REP(j,0,m-1) if (S>>j&1) {
                    chkmax(r,dp[S^1<<j]);
                }
            }
            else if (f[i]==2) {
                r = INF;
                REP(j,0,n-1) if (S>>j&1) {
                    chkmin(r,dp[S^1<<j]-a[j]);
                }
            }
            else if (f[i]==3) {
                r = -INF;
                REP(j,0,n-1) if (S>>j&1) {
                    chkmax(r,dp[S^1<<j]+a[j]);
                }
            }
        }
        printf("%d
    ",dp[mx]);
    }
    O(m2^m) 

    377D Developing Game

    大意: $n$个工人, 第$i$个工人属性$v_i$, 只能和属性范围$[L_i,R_i]$的人一起工作, 求最多选出多少工人.

    这道题还是挺有意思的, 刚开始想了一个$dp$的做法, 用树套树优化, 但是数据范围太大了, 很难卡过.

    实际上可以直接考虑最终确定的区间$[L,R]$, 那么一个工人$(L_i,v_i,R_i)$会对所有$L_ile Lle v_i,v_ile Rle R_i$的区间产生贡献. 这样就转化为二维区间加, 最终查询所有点最值, 可以用线段树扫描线很容易实现.

    #include <iostream>
    #include <sstream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <cstring>
    #include <bitset>
    #include <functional>
    #include <random>
    #define REP(i,a,n) for(int i=a;i<=n;++i)
    #define PER(i,a,n) for(int i=n;i>=a;--i)
    #define hr putchar(10)
    #define pb push_back
    #define lc (o<<1)
    #define rc (lc|1)
    #define mid ((l+r)>>1)
    #define ls lc,l,mid
    #define rs rc,mid+1,r
    #define x first
    #define y second
    #define io std::ios::sync_with_stdio(false)
    #define endl '
    '
    #define DB(a) ({REP(__i,1,n) cout<<a[__i]<<' ';hr;})
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int P = 1e9+7, INF = 0x3f3f3f3f;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
    ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
    inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
    //head
    
    
    
    
    const int N = 1e6+10;
    int n, cnt, mx;
    struct {
        int l,v,r;
    } e[N];
    struct _ {
        int l,r,h,v;
    } a[N];
    struct node {
        int mx,tag,pos;
        void upd(int x) {mx+=x,tag+=x;}
        node operator + (const node &rhs) const {
            node ret;
            ret.mx = max(mx,rhs.mx);
            ret.pos = ret.mx==mx?pos:rhs.pos;
            ret.tag = 0;
            return ret;
        }
    } tr[N<<2];
    
    void pd(int o) {
        if (tr[o].tag) {
            tr[lc].upd(tr[o].tag);
            tr[rc].upd(tr[o].tag);
            tr[o].tag=0;
        }
    }
    void add(int o, int l, int r, int ql, int qr, int v) {
        if (ql<=l&&r<=qr) return tr[o].upd(v);
        pd(o);
        if (mid>=ql) add(ls,ql,qr,v);
        if (mid<qr) add(rs,ql,qr,v);
        tr[o] = tr[lc]+tr[rc];
    }
    void build(int o, int l, int r) {
        tr[o].mx=tr[o].tag=0,tr[o].pos=l;
        if (l!=r) build(ls),build(rs);
    }
    
    int main() {
        cin>>n;
        REP(i,1,n) { 
            cin>>e[i].l>>e[i].v>>e[i].r;
            a[++cnt] = {e[i].l,e[i].v,e[i].v,1};
            a[++cnt] = {e[i].l,e[i].v,e[i].r+1,-1};
            mx = max(mx, e[i].r+1);
        }
        sort(a+1,a+1+cnt,[](_ a,_ b){return a.h<b.h;});
        build(1,1,mx);
        int now = 1, ans = 0;
        pii pos;
        REP(i,1,mx) {
            while (now<=cnt&&a[now].h<=i) add(1,1,mx,a[now].l,a[now].r,a[now].v),++now;
            if (tr[1].mx>ans) {
                ans = tr[1].mx;
                pos = pii(tr[1].pos,i);
            }
        }
        printf("%d
    ", ans);
        REP(i,1,n) {
            if (e[i].l<=pos.x&&pos.x<=e[i].v&&e[i].v<=pos.y&&pos.y<=e[i].r) {
                printf("%d ",i);
            }
        }
        puts("");
    }
    View Code

    377E Cookie Clicker

    大意: $n$种建筑, 第$i$个花费$c_i$个曲奇, 每秒生产$v_i$曲奇. 每秒钟只能选一个建筑工作. 初始时刻$0$, 曲奇数$0$, 若$t$时刻选择一个建筑工作, 那么$t+1$时刻得到收益. 求得到$s$块曲奇最少用时.

    斜率优化dp

    include <iostream>
    #include <sstream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <cstring>
    #include <bitset>
    #include <functional>
    #include <random>
    #define REP(i,a,n) for(int i=a;i<=n;++i)
    #define PER(i,a,n) for(int i=n;i>=a;--i)
    #define hr putchar(10)
    #define pb push_back
    #define lc (o<<1)
    #define rc (lc|1)
    #define mid ((l+r)>>1)
    #define ls lc,l,mid
    #define rs rc,mid+1,r
    #define x first
    #define y second
    #define io std::ios::sync_with_stdio(false)
    #define endl '
    '
    #define DB(a) ({REP(__i,1,n) cout<<a[__i]<<' ';hr;})
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int P = 1e9+7, INF = 0x3f3f3f3f;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
    ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
    inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
    //head
    
    
    
    const int N = 1e6+10;
    int n;
    ll s, dp[N];
    struct _ {
        ll c, v;
        bool operator < (const _ &rhs) const {
            return c<rhs.c||c==rhs.c&&v<rhs.v;
        }
    } a[N];
    
    ll slope2(int i, int j) {
        return (a[j].v-a[i].v-1+dp[i]-dp[j])/(a[j].v-a[i].v);
    }
    ll chk(int i, int j, int k) {
        return slope2(i,j)>=slope2(j,k);
    }
    ll slope(int i, int j) {
        return (dp[i]-dp[j])/(a[j].v-a[i].v);
    }
    
    int main() {
        cin>>n>>s;
        REP(i,1,n) cin>>a[i].v>>a[i].c;
        sort(a+1,a+1+n);
        memset(dp,INF,sizeof dp);    
        deque<int> q;
        ll ans = 1e18;
        REP(i,1,n) {
            if (q.size()&&a[q.back()].v>=a[i].v) continue;
            while (q.size()>1&&slope(q[0],q[1])*a[q[0]].v+dp[q[0]]<a[i].c) q.pop_front();
            if (i==1) dp[i] = 0;
            else if (q.size()) {
                ll t = (a[i].c-dp[q[0]]+a[q[0]].v-1)/a[q[0]].v;
                ll rem = t*a[q[0]].v+dp[q[0]]-a[i].c;
                dp[i] = rem-t*a[i].v;
            }
            else continue;
            ans = min(ans, (s-dp[i]+a[i].v-1)/a[i].v);
            while (q.size()>1&&chk(q[q.size()-2],q.back(),i)) q.pop_back();
            q.push_back(i);
        }
        printf("%lld
    ", ans);
    }
    View Code
  • 相关阅读:
    React 组件生命周期
    React Ant Design Mobile 中 ListView 简单使用,搞懂每一行代码
    .net网站自动化部署-致两年前的遗留的问题
    【479】cross-entropy与softmax的求导
    【478】Victor Zhou深度学习链接
    网站高并发大流量访问的处理及解决方案
    年轻人的第一个 Docker 应用,大大提高生产力!
    Spring Boot 静态资源处理,妙!
    Spring 配置最好不要配置 xsd 版本号!
    自己动手实现一个简单的 IOC,牛皮!!
  • 原文地址:https://www.cnblogs.com/uid001/p/11298911.html
Copyright © 2020-2023  润新知