zoukankan      html  css  js  c++  java
  • 《Codeforces Round #661 (Div. 3)》

    A:读错题导致难度飙升。

    这里题意是任意两个下标满足条件都能换,那就是个水题了

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef long double ld;
    typedef pair<LL,int> pii;
    const int N = 1e5+5;
    const int M = 1e6+5;
    const LL Mod = 998244353;
    #define rg register
    #define pi acos(-1)
    #define INF 1e8
    #define INM INT_MIN
    #define dbg(ax) cout << "now this num is " << ax << endl;
    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;
    }
    int a[55],vis[105];
    int main()
    {
        int ca;ca = read();
        while(ca--)
        {
            int n;n = read();
            memset(vis,0,sizeof(vis));
            for(int i = 1;i <= n;++i)
            {
                a[i] = read();
                vis[a[i]]++;
            }
            sort(a+1,a+n+1);
            int f = 0;
            for(int i = 1;i < n;++i)
            {
                if(vis[a[i]+1] != 0) continue;
                if(vis[a[i]] > 1){vis[a[i]]--;continue;}
                f = 1;
            }
            if(f) printf("NO\n");
            else printf("YES\n");
        }
      //  system("pause");
        return 0;
    }
    View Code

    B:水题

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef long double ld;
    typedef pair<LL,int> pii;
    const int N = 1e3+5;
    const int M = 1e6+5;
    const LL Mod = 998244353;
    #define rg register
    #define pi acos(-1)
    #define INF 1e18
    #define INM INT_MIN
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline LL read()
    {
        LL 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;
    }
    LL a[55],b[55];
    int main()
    {
        int ca;ca = read();
        while(ca--)
        {
            int n;n = read();
            LL mi1 = INF,mi2 = INF;
            for(int i = 1;i <= n;++i) a[i] = read(),mi1 = min(mi1,a[i]);
            for(int i = 1;i <= n;++i) b[i] = read(),mi2 = min(mi2,b[i]);
            LL ans = 0; 
            for(int i = 1;i <= n;++i)
            {
                int dis = a[i]-mi1;
                ans += dis;
                int ma = b[i]-mi2;
                if(ma > dis) ans += ma-dis;   
           //     dbg(ans);
            }
            printf("%lld\n",ans);
        }
       // system("pause");
        return 0;
    }
    View Code

    C:一开始想到二分,但发现不满足二分性质。

    但是这也为解题提供了一个思路,可以发现组合的权值最多只有[1,100]的可能性,那么取枚举这个权值即可

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef long double ld;
    typedef pair<LL,int> pii;
    const int N = 1e3+5;
    const int M = 1e6+5;
    const LL Mod = 998244353;
    #define rg register
    #define pi acos(-1)
    #define INF 1e18
    #define INM INT_MIN
    #define dbg(ax) cout << "now this num is " << ax << endl;
    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;
    }
    int w[55],n,vis[105],num[105];
    int check(int x)
    {
        for(int i = 0;i <= 100;++i) num[i] = vis[i];
        int ans = 0;
        for(int i = 1;i <= n;++i)
        {
            if(w[i] > x) continue;
            if(x-w[i] == w[i])
            {
                if(num[w[i]] > 1) num[w[i]] -= 2,ans++;
            }
            else if(num[x-w[i]] > 0 && num[w[i]] > 0)
            {
                num[x-w[i]]--;
                num[w[i]]--;
                ans++;
            }
        }
        return ans;
    }
    int main()
    {
        int ca;ca = read();
        while(ca--)
        {
            n = read();
            memset(vis,0,sizeof(vis));
            for(int i = 1;i <= n;++i) w[i] = read(),vis[w[i]]++;
            int ans = 0;
            for(int i = 1;i <= 100;++i) ans = max(ans,check(i));
            printf("%d\n",ans);
        }
      //  system("pause");
        return 0;
    }
    View Code

    D:感觉我想的稍微麻烦了。。能AC就是好题解(逃

    可以发现对于每个1,我们要将后面的没有被接入的第一个0接入当前序列。(0也是同理)

    这样显然是可以满足最小的子序列数的。

    那么对于这个后面的最小位置,我们可以用线段树维护这个位置。

    然后一个位置被接入,就去更新线段树。因为是单点更新,复杂度nlogn,也挺快了。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef long double ld;
    typedef pair<LL,int> pii;
    const int N = 2e5+5;
    const int M = 1e6+5;
    const LL Mod = 998244353;
    #define rg register
    #define pi acos(-1)
    #define INF 1e8
    #define INM INT_MIN
    #define dbg(ax) cout << "now this num is " << ax << endl;
    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;
    }
    int ans[N];//0,1
    char s[N];
    struct Node{int L,r,mi;}node[2][N<<2];
    void build(int L,int r,int idx,int id)//id-0,id-1
    {
        node[id][idx].L = L,node[id][idx].r = r;
        if(L == r)
        {
            if(s[L] == '0' && id == 0 || s[L] == '1' && id == 1) node[id][idx].mi = L;
            else node[id][idx].mi = INF;
            return ;
        }
        int mid = (L+r)>>1;
        build(L,mid,idx<<1,id);
        build(mid+1,r,idx<<1|1,id);
        node[id][idx].mi = min(node[id][idx<<1].mi,node[id][idx<<1|1].mi);
    }
    void update(int x,int idx,int id)
    {
        if(node[id][idx].L == node[id][idx].r)
        {
            node[id][idx].mi = INF;
            return ;
        }
        int mid = (node[id][idx].L + node[id][idx].r)>>1;
        if(mid >= x) update(x,idx<<1,id);
        else update(x,idx<<1|1,id);
        node[id][idx].mi = min(node[id][idx<<1].mi,node[id][idx<<1|1].mi);
    }
    int query_mi(int L,int r,int idx,int id)
    {
        if(node[id][idx].L >= L && node[id][idx].r <= r) return node[id][idx].mi;
        int mid = (node[id][idx].L+node[id][idx].r)>>1,mi = INF;
        if(mid >= L) mi = min(mi,query_mi(L,r,idx<<1,id));
        if(mid < r) mi = min(mi,query_mi(L,r,idx<<1|1,id));
        return mi;
    }
    int main()
    {
        int ca;ca = read();
        while(ca--)
        {
            int n;n = read();
            scanf("%s",s+1);
            build(1,n,1,0);
            build(1,n,1,1);
            int ma = 0;
            memset(ans,0,sizeof(ans));
            for(int i = 1;i <= n;++i)
            {
                if(ans[i] == 0) ans[i] = ++ma;
                int tmp;
                if(s[i] == '0') tmp = query_mi(i+1,n,1,1);
                else tmp = query_mi(i+1,n,1,0);
                if(tmp == INF) continue;
                ans[tmp] = ans[i];
                if(s[tmp] == '0') update(tmp,1,0);
                else update(tmp,1,1);
            }
            printf("%d\n",ma);
            for(int i = 1;i <= n;++i) printf("%d%c",ans[i],i == n ? '\n' : ' ');
        }
        //system("pause");
        return 0;
    }
    View Code

    E1:读错题导致难度飙升(梅开二度,老笨蛋了)

    注意的是,这里是要使总(root-leaves)路径权值和小于s。

    那么,我们可以去记录路径被经过的次数,然后乘上这个路径的w-w/2,这就是让它折半一次的能对总权值减少的贡献。

    那么显然我们每次都选最大的,就能在最少的次数内满足。

    这里这个被经过次数很显然就是子节点数。堆来维护最大值即可

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef long double ld;
    typedef pair<LL,int> pii;
    const int N = 1e5+5;
    const int M = 1e6+5;
    const LL Mod = 998244353;
    #define rg register
    #define pi acos(-1)
    #define INF 1e18
    #define INM INT_MIN
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline LL read()
    {
        LL 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;
    }
    struct Node{int to;LL dis;};
    vector<Node> G[N];
    int ssize[N];
    LL sum = 0;
    struct Point{
        LL cost,w,cnt;
        bool operator < (const Point &a)const{
            return cost < a.cost;
        }
    };
    priority_queue<Point> Q;
    LL cal(LL w,int cnt)
    {
        return 1LL*cnt*(w-w/2);
    }
    void dfs(int u,int fa,LL dis)
    {
        if(G[u].size() == 1) ssize[u] = 1;
        for(auto v : G[u])
        {
            if(v.to == fa) continue;
            dfs(v.to,u,v.dis);
            ssize[u] += ssize[v.to];
        }
        if(dis != 0) 
        {
            //printf("dis is %lld u is %d ssize is %d\n",dis,u,ssize[u]);
            sum += 1LL*ssize[u]*dis;
            Q.push(Point{cal(dis,ssize[u]),dis,ssize[u]});
        }
    }
    int main()
    {
        int ca;ca = read();
        while(ca--)
        {
            int n;LL s;
            n = read(),s = read();
            for(rg int i = 1;i <= n;++i) G[i].clear(),ssize[i] = 0;
            for(rg int i = 1;i < n;++i)
            {
                int u,v;LL w;
                u = read(),v = read(),w = read();
                G[u].push_back(Node{v,w});
                G[v].push_back(Node{u,w});
            }
            while(!Q.empty()) Q.pop();
            sum = 0;
            dfs(1,0,0);
            int ans = 0;
            while(!Q.empty() && sum > s)
            {
                ans++;
                Point q = Q.top();
                Q.pop();
                sum -= q.cost;
                q.w /= 2;
                q.cost = cal(q.w,q.cnt);
                Q.push(q);
            }
            printf("%d\n",ans);
        }
       // system("pause");
        return 0;
    }
    View Code

    E2:最小化花费了,可以用二分来。

    因为c只有1,2,那么我们可以去维护两个堆。

    一个维护1,一个维护2。开两个前缀和数组

    用数组1来维护花费代价为i时能减少的最大权值。

    数组2来维护花费代价为2*i时能减少的最大权值。

    我们枚举1的花费,然后去二分最小的2代价使得sum-两个前缀和数组和 <= s

    memset初始化数组T了,其实没必要,只要让第0个为0即可(改了之后快的飞起~~芜湖)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef long double ld;
    typedef pair<LL,int> pii;
    const int N = 1e5+5;
    const int M = 2e6+5;
    const LL Mod = 998244353;
    #define rg register
    #define pi acos(-1)
    #define INF 1e18
    #define INM INT_MIN
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline LL read()
    {
        LL 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;
    }
    struct Node{int to;LL dis,cost;};
    vector<Node> G[N];
    struct Point{
        int cnt;LL w,cost;
        bool operator < (const Point &a)const{
            return cost < a.cost;
        }
    };
    LL cal(LL w,int cnt)
    {
        return 1LL*cnt*(w-w/2);
    }
    priority_queue<Point> Q1,Q2;
    int ssize[N];
    LL sum = 0,pre1[M],pre2[M],s;
    void dfs(int u,int fa,LL dis,int c)
    {
        if(G[u].size() == 1) ssize[u] = 1;
        for(auto v : G[u])
        {
            if(v.to == fa) continue;
            dfs(v.to,u,v.dis,v.cost);
            ssize[u] += ssize[v.to];
        }
        if(dis != 0)
        {
            sum += 1LL*ssize[u]*dis;
            if(c == 1) Q1.push(Point{ssize[u],dis,cal(dis,ssize[u])});
            else Q2.push(Point{ssize[u],dis,cal(dis,ssize[u])});
        }
    }
    bool check(LL tmp,int x)
    {
        return (tmp-pre2[x]) <= s;
    }
    int main()
    {
        int ca;ca = read();
        while(ca--)
        {
            int n;
            n = read(),s = read();
            for(int i = 1;i <= n;++i) G[i].clear(),ssize[i] = 0;
            for(rg int i = 1;i < n;++i)
            {
                int u,v,w,c;
                u = read(),v = read(),w = read(),c = read();
                G[u].push_back(Node{v,w,c});
                G[v].push_back(Node{u,w,c});
            }
            while(!Q1.empty()) Q1.pop();
            while(!Q2.empty()) Q2.pop();
            pre1[0] = pre2[0] = sum = 0;
            dfs(1,0,0,0);
            int cnt1 = 0,cnt2 = 0;
            while(!Q1.empty() && sum-pre1[cnt1] > s)
            {
                Point q = Q1.top();Q1.pop();
                ++cnt1;
                pre1[cnt1] = pre1[cnt1-1]+q.cost;
                q.w /= 2;
                q.cost = cal(q.w,q.cnt);
                if(q.cost != 0) Q1.push(q);
            }
            while(!Q2.empty() && sum-pre2[cnt2] > s)
            {
                Point q = Q2.top();Q2.pop();
                ++cnt2;
                pre2[cnt2] = pre2[cnt2-1]+q.cost;
                q.w /= 2;
                q.cost = cal(q.w,q.cnt);
                if(q.cost != 0) Q2.push(q);
            }
            LL ans = INF;
            for(int i = 0;i <= cnt1;++i)
            {
                LL ma = sum-pre1[i];
                int L = 0,r = cnt2,ta = 1e8;
                while(L <= r)
                {
                    int mid = (L+r)>>1;
                    if(check(ma,mid))
                    {
                        ta = mid;
                        r = mid-1;
                    } 
                    else L = mid+1;
                }
                ans = min(ans,1LL*i+ta*2);
            }
            printf("%lld\n",ans);
        }
        //system("pause");
        return 0;
    }
    View Code

    F:区间dp的思想

    我们可以先处理出每个区间内部能嵌套的最多区间数,然后就找到了这个区间的最大权值。

    既然要去找内部的嵌套,那么显然满足内部区间的长度比该区间小,所以我们可以按长度排序。

    然后dp,因为已经按长度排序了,所以dp时肯定内部的权值已经处理好了。

    具体的dp:

    如果内部有个区间,且这个区间前面没有可以和它连接的,那么直接dp转移就行。

    如果有相连的区间,我们可以让dp时一直传递值。

    那么由于这里很特殊的一个地方,如果两个连续的区间,他们相接的地方重合,那么这两个区间是无法相连的。

    所以我们对于当前区间,从p[i.]L-1]来转移,就不会重叠了

    我们把满足条件的内部区间放入,然后当前位置满足由区间为右端点,就从左端点转移。

    数据过大,先离散化。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef long double ld;
    typedef pair<LL,int> pii;
    const int N = 2e5+5;
    const int M = 2e6+5;
    const LL Mod = 998244353;
    #define rg register
    #define pi acos(-1)
    #define INF 1e18
    #define INM INT_MIN
    #define dbg(ax) cout << "now this num is " << ax << endl;
    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;
    }
    struct Node{int L,r,len,id;}p[N];
    bool cmp(Node a,Node b){return a.len < b.len;}
    int a[N<<1],n,cnt;
    LL dp[N],f[N];//到i号
    vector<Node> G[N];
    void slove()
    {
        p[n+1] = {1,cnt+1,cnt+1,n+1};
        sort(p+1,p+n+2,cmp);
        for(int i = 1;i <= n+1;++i)
        {
            for(int j = p[i].L-1;j <= p[i].r;++j) G[j].clear(),dp[j] = 0;
            for(int j = 1;j < i;++j)
            {
                if(p[j].L >= p[i].L && p[j].r <= p[i].r) G[p[j].r].push_back(p[j]);
            }
            for(int j = p[i].L;j <= p[i].r;++j)
            {
                dp[j] = dp[j-1];//先继承
                for(auto t : G[j])//如果有线段的右边界为它
                {
                    dp[j] = max(dp[j],dp[t.L-1]+f[t.id]);
                }
            }
            f[p[i].id] = dp[p[i].r]+1;
        }
        printf("%lld\n",f[n+1]-1);
    }
    int main()
    {
        int ca;ca = read();
        while(ca--)
        {
            memset(f,0,sizeof(f));
            n = read();
            cnt = 0;
            for(int i = 1;i <= n;++i)
            {
                p[i].L = read(),p[i].r = read(),p[i].id = i;
                a[++cnt] = p[i].L,a[++cnt] = p[i].r;
            }
            sort(a+1,a+cnt+1);
            cnt = unique(a+1,a+cnt+1)-a-1;
            for(int i = 1;i <= n;++i)
            {
                p[i].L = lower_bound(a+1,a+cnt+1,p[i].L)-a;
                p[i].r = lower_bound(a+1,a+cnt+1,p[i].r)-a;
                p[i].len = p[i].r-p[i].L;
            }
            slove();
        }
        system("pause");
        return 0;
    }
    
    /*
    4
    5
    1 5
    2 3
    2 5
    3 5
    2 2
    
    */
    View Code
  • 相关阅读:
    Java Web Start应用管理
    搭建java开发环境需要什么软件,怎么搭建java开发环境?
    制作WinPE
    今天看见.do网页,疑惑,这是什么文件??又是什么新技术??查了一下
    VC用ADO访问数据库全攻略
    ASP连接11种数据库语法总结
    asp.net里导出excel表方法汇总
    ASP.NET 发邮件方法
    ASP.NET 网站开发日常异常总汇(持续更新)
    javascript操作JSON
  • 原文地址:https://www.cnblogs.com/zwjzwj/p/13497004.html
Copyright © 2011-2022 走看看