zoukankan      html  css  js  c++  java
  • 《补题solution》

    出题人卡的真的好.

    宇佐大人的白旗 ~ Most Famous Hero:

    这题有点无语了,比赛的时候数据出问题了,害我一直出问题,最后数据修了就过了。

    做法1:直接最短路上更新就好了。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<LL,int> pii;
    const int N = 1e4 + 5;
    const int M = 2e3 + 5;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e18
    #define dbg(ax) cout << "now this num is " << ax << endl;
    namespace FASTIO{
        inline int read(){
            int x = 0,f = 1;char c = getchar();
            while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
            while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
            return x*f;
        }
    }
    using namespace FASTIO;
    
    int n,m,c[N],p[N],s,t;
    LL dis[N];
    struct Node{int to,dis;};
    vector<Node> G[N];
    
    void solve() {
        for(int i = 1;i <= n;++i) dis[i] = INF;
        priority_queue<pii,vector<pii>,greater<pii> > Q;
        dis[s] = c[s] - p[s];
        Q.push(pii{dis[s],s});
        while(!Q.empty()) {
            int u = Q.top().second;
            LL d = Q.top().first;
            Q.pop();
            if(d > dis[u]) continue;
            for(auto v : G[u]) {
                LL tmp = dis[u] + v.dis;
                LL ma = tmp + c[v.to] - p[v.to];
                if(v.to == t || ma < tmp) tmp = ma;
                if(tmp < dis[v.to]) {
                    dis[v.to] = tmp;
                    Q.push(pii{dis[v.to],v.to});
                }
            }
        }
    }   
    int main() {
        n = read(),m = read();
        for(int i = 1;i <= n;++i) c[i] = read();
        for(int i = 1;i <= n;++i) p[i] = read();
        while(m--) {
            int u,v,w;u = read(),v = read(),w = read();
            G[u].push_back(Node{v,w});
        }
        s = read(),t = read();
        solve();
        printf("%lld
    ",dis[t]);
       // system("pause");
        return 0;
    }
    View Code

    做法2:当数据量变大,做法1的复杂度可能就会比较高,因为这条线路一定从S出发,到T结束。

    那么就以S为根来建一棵树,注意是有向的,也就是有向无环图,然后就可以拓扑排序了。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<LL,int> pii;
    const int N = 1e4 + 5;
    const int M = 2e3 + 5;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e18
    #define dbg(ax) cout << "now this num is " << ax << endl;
    namespace FASTIO{
        inline int read(){
            int x = 0,f = 1;char c = getchar();
            while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
            while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
            return x*f;
        }
    }
    using namespace FASTIO;
    
    int n,m,c[N],p[N],s,t,in[N],a[N];
    LL dis[N];
    bool vis[N];
    struct Node{int to,dis;};
    vector<Node> G[N],vec[N];
    
    void dfs(int u) {
        vis[u] = 1;
        for(auto v : G[u]) {
            if(!vis[v.to]) {
                dfs(v.to);
            }
        }
    }
    void solve() {
        for(int i = 1;i <= n;++i) dis[i] = INF;
        queue<int> Q;
        Q.push(s);
        dis[s] = 0;
        while(!Q.empty()) {
            int u = Q.front();
            Q.pop();
            for(auto v : vec[u]) {
                in[v.to]--;
                LL ma = dis[u] + v.dis;
                if(v.to != s && v.to != t && a[v.to] <= 0) ma += a[v.to];
                dis[v.to] = min(dis[v.to],ma);
                if(in[v.to] == 0) {
                    Q.push(v.to);
                }
            }
        }
    }
    int main() {
        n = read(),m = read();
        for(int i = 1;i <= n;++i) c[i] = read();
        for(int i = 1;i <= n;++i) p[i] = read(),a[i] = c[i] - p[i];
        while(m--) {
            int u,v,w;u = read(),v = read(),w = read();
            G[u].push_back(Node{v,w});
        }
        s = read(),t = read();
        dfs(s);
        for(int i = 1;i <= n;++i) {
            if(vis[i] == 0) continue;
            for(auto v : G[i]) {
                if(vis[v.to] == 0) continue;
                vec[i].push_back(Node{v.to,v.dis});
                in[v.to]++;
            }
        }
        solve();
        printf("%lld
    ",dis[t] + a[s] + a[t]);
      //  system("pause");
        return 0;
    }
    View Code

     飘上月球不死之烟 ~ Elixir of Life:

    很裸的线段树,但是这里内存卡的很紧,如果用结构体来建树,就会爆内存。

    所以就用数组来,同时,这里普通的线段树常数卡的好,也能过。

    我们考虑对线段树进行一些优化。

    首先很显然可以想到倒着进行修改,那么一个被修改过的位置,它的大小写就固定了。我们就打上标记。

    对于一个位置最多修改一下,这样平推下来复杂度就是nlogn。

    同时最后我们一直query就下放所有颜色, 这样比遍历然后单点询问要快一点。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<LL,int> pii;
    const int N = 1e6 + 5;
    const int M = 2e3 + 5;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e18
    #define dbg(ax) cout << "now this num is " << ax << endl;
    #define DBG(bx,ax) cout << bx << " is " << ax << endl;
    namespace FASTIO{
        inline int read(){
            int x = 0,f = 1;char c = getchar();
            while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
            while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
            return x*f;
        }
    }
    using namespace FASTIO;
    
    int m,tag[N << 2],k[N << 2],sum[N << 2];
    int id[N],L[N],r[N];
    void Pushup(int idx) {
        sum[idx] = sum[idx << 1] + sum[idx << 1 | 1];
    }
    void Pushdown(int L,int r,int idx) {
        if(tag[idx] != 0) {        
            int mid = (L + r) >> 1;
            if(sum[idx << 1] != mid - L + 1) {
                sum[idx << 1] = mid - L + 1;
                tag[idx << 1] = tag[idx];
                k[idx << 1] = tag[idx];
            } 
            if(sum[idx << 1 | 1] != r - mid) {
                sum[idx << 1 | 1] = r - mid;
                tag[idx << 1 | 1] = tag[idx];
                k[idx << 1 | 1] = tag[idx];
            }
            tag[idx] = 0;
        }
    }
    void update(int le,int ri,int L,int r,int idx,int val) {
        if(le >= L && ri <= r) {
            tag[idx] = k[idx] = val;
            sum[idx] = ri - le + 1;
            return ;
        }
        Pushdown(le,ri,idx);
        int mid = (le + ri) >> 1;
        if(mid >= L) {
            if(sum[idx << 1] != mid - le + 1) {
                update(le,mid,L,r,idx << 1,val);
            }
        }
        if(mid < r) {
            if(sum[idx << 1 | 1] != ri - mid) update(mid + 1,ri,L,r,idx << 1 | 1,val);
        }
        Pushup(idx);
    }
    void query(int L,int r,int idx) {
        if(L == r) {
            id[L] = k[idx];
            return ;
        }
        Pushdown(L,r,idx);
        int mid = (L + r) >> 1;
        if(sum[idx << 1] != 0) query(L,mid,idx << 1);
        if(sum[idx << 1 | 1] != 0) query(mid + 1,r,idx << 1 | 1);
    }
    char cal1(char c) {
        if(c >= 'a' && c <= 'z') return c;
        else return c + 32;
    }
    char cal2(char c) {
        if(c >= 'A' && c <= 'Z') return c;
        else return c - 32;
    }
    int main() {
        m = read();
        string s;getline(cin,s);
        int n = s.size();
        for(int i = 1;i <= m;++i) id[i] = read(),L[i] = min(n,read()),r[i] = min(n,read());
        for(int i = m;i >= 1;--i) {
            update(1,n,L[i],r[i],1,id[i]);
        }
        memset(id,0,sizeof(id));
        query(1,n,1);
        for(int i = 1;i <= n;++i) {
            //printf("i is %d val is %d
    ",i,id[i]);
            if(s[i - 1] == ' ') printf(" ");
            else {
                if(id[i] == 0) printf("%c",s[i - 1]);
                else if(id[i] == 1) printf("%c",cal1(s[i - 1]));
                else if(id[i] == 2) printf("%c",cal2(s[i - 1]));
                else {
                    if(i == 1) printf("%c",cal2(s[i - 1]));
                    else if(s[i - 2] == ' ') printf("%c",cal2(s[i - 1]));
                    else printf("%c",cal1(s[i - 1]));
                }
            }
        }   
        //system("pause");
        return 0;
    }
    /*
    5
    ABC DADN A adi da D
    1 3 3
    1 3 10
    3 3 10
    2 2 10
    1 2 2
    */
    View Code

    Locked Girl ~ 少女密室:

    那么我们可以考虑当前完成了所有删除操作,然后只需要添加操作即可。

    显然如果要删除后的代码1,添加一些就可以得到代码2。

    那么这段删除后的代码,一定是代码1和代码2的公共子序列。

    假设删去的长度为x,代码1长度len1,代码2长度len2。

    那么对于需要添加的字符串长度就是len2 - (len1 - x) = len1 - len2 + x就是操作的数量。

    那么我们需要操作的次数就是len1 - len2 + 2 * x.

    显然x越小,我们操作的次数越小,x越小也就是表示要公共子序列越大,那么很显然就是求最长公共子序列了。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<LL,int> pii;
    const int N = 1e6 + 5;
    const int M = 2e3 + 5;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e18
    #define dbg(ax) cout << "now this num is " << ax << endl;
    #define DBG(bx,ax) cout << bx << " is " << ax << endl;
    namespace FASTIO{
        inline int read(){
            int x = 0,f = 1;char c = getchar();
            while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
            while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
            return x*f;
        }
    }
    using namespace FASTIO;
    
    int dp[305][305],n,m;
    string a[305],b[305];
    int main() {
        n = read();
        for(int i = 1;i <= n;++i) getline(cin,a[i]);
        m = read();
        for(int i = 1;i <= m;++i) getline(cin,b[i]);
        for(int i = 1;i <= n;++i) {
            for(int j = 1;j <= m;++j) {
                if(a[i] == b[j]) dp[i][j] = max(dp[i][j],dp[i - 1][j - 1] + 1);
                else dp[i][j] = max(dp[i - 1][j],dp[i][j - 1]);
            }
        }
        int ans = n - dp[n][m] + m - dp[n][m];
        printf("%d
    ",ans);
      //  system("pause");
        return 0;
    }
    View Code

    回忆京都 ~ Retrospective Kyoto:

    这题还是有点意思的,要推到结论需要思考时间。

    首先,对于该图的任意一棵生成树tree(所有点都在该树上),都必定存在一种方法满足条件。

    方法就是从叶子开始往上走,每次都从父亲走到儿子,注意要一个父节点的所有儿子都走完,再将这个父节点往上。

    dfs来找一棵生成树即可。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    const int N = 1e6 + 5;
    const int M = 2e3 + 5;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e18
    #define dbg(ax) cout << "now this num is " << ax << endl;
    #define DBG(bx,ax) cout << bx << " is " << ax << endl;
    namespace FASTIO{
        inline int read(){
            int x = 0,f = 1;char c = getchar();
            while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
            while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
            return x*f;
        }
    }
    using namespace FASTIO;
    
    vector<int> G[N];
    bool vis[N];
    vector<pii> ans;
    void dfs(int u) {
        vis[u] = 1;
        for(auto v : G[u]) {
            if(!vis[v]) {
                ans.push_back(pii{u,v});
                dfs(v);
            }
        }
    }
    
    int main() {
        int n,m;n = read(),m = read();
        while(m--) {
            int u,v;u = read(),v = read();
            G[u].push_back(v);
            G[v].push_back(u);
        }
        dfs(1);
        if(ans.size() != n - 1) printf("Impossible!
    ");
        else {
            for(int i = ans.size() - 1;i >= 0;--i) {
                printf("%d -> %d
    ",ans[i].first,ans[i].second);
            }
        }
        //system("pause");
        return 0;
    }
    View Code

    青木原的传说 ~ Forbidden Forest:

    这题卡vector,最后用了链式前向星才过的。

    一开始看成连通块一起减导致贪心错误,换根的思路也误导了自己。

    这里正确的贪心思路应该是从叶子节点往上。

    我们考虑对于节点u,它的子树已经完成了归0,那么节点u它的消去路径,只有两种情况。

    1:从u往fa走的一条链。

    2:从u到fa另一个子节点v的一条链。

    这里方案2一次可以减少两个儿子的1,然后方案1只能减少一个儿子的1,所以方案2肯定比方案1优。

    那么我们在能用方案2的时候就尽量用方案2.

    将所有子节点的贡献放入大顶堆,大顶堆能保证我们最后实行方案1,可操作的子节点值是最大的,这样就能最大化利用u的这条链。

    这里在堆里操作的时候每次都要一个一个减,然后重新放入堆,这样也是为了保证最后得到的堆顶的子节点值是当前最优的。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<LL,int> pii;
    const int N = 5e5 + 5;
    const int M = 2e3 + 5;
    const LL Mod = 100000007;
    #define pi acos(-1)
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    
    int n,m,a[N];
    LL ans = 0;
    bool vis[N];
    int head[N],tot = 0;
    struct Node{int to,next;}e[N << 1];
    void add(int u,int v) {
        e[++tot].to = v,e[tot].next = head[u],head[u] = tot;
        e[++tot].to = u,e[tot].next = head[v],head[v] = tot;
    }
    void dfs(int u,int fa) {
        vis[u] = 1;
        priority_queue<int,vector<int>,less<int> > Q;
        for(int i = head[u];i;i = e[i].next) {
            int v = e[i].to;
            if(v == fa) continue;
            dfs(v,u);
            if(a[v] != 0) Q.push(a[v]);
        }
        while(a[u] != 0 && Q.size() > 1) {
            int x = Q.top();
            Q.pop();
            int y = Q.top();
            Q.pop();
            x--,y--,ans--,a[u]--;
            if(x != 0) Q.push(x);
            if(y != 0) Q.push(y);
        }
        ans += a[u];
        if(Q.size() > 0) {
            int x = Q.top();
            Q.pop();
            if(a[u] >= x) ans -= x;
            else ans -= a[u];
        }
    }
    int main() {
        scanf("%d %d",&n,&m);
        for(int i = 1;i <= n;++i) scanf("%d",&a[i]);
        while(m--) {
            int u,v;scanf("%d %d",&u,&v);
            add(u,v);
        }
        for(int i = 1;i <= n;++i) {
            if(vis[i] == 1) continue;
            dfs(i,0);
        }
        printf("%lld
    ",ans);
        system("pause");
        return 0;
    }
    View Code

     

  • 相关阅读:
    Django学习笔记第六篇--实战练习二--简易实现登录注册功能demo
    追踪溯源--抓住隐藏在NAT后面的罪犯
    Linux内核态、用户态简介与IntelCPU特权级别--Ring0-3
    Windows2008 IIS配置FTP站点
    .NET RSA解密、签名、验签
    Quartz.NET 入门
    使用Topshelf创建Windows服务
    xcode6 新建项目真机调试无法全屏
    .NET 二维码生成(ThoughtWorks.QRCode)
    iOS手机应用开发原型模板及开发流程
  • 原文地址:https://www.cnblogs.com/zwjzwj/p/15090783.html
Copyright © 2011-2022 走看看