zoukankan      html  css  js  c++  java
  • 2020武大校赛预赛C题

    1. 直接借助栈、差分模拟

    pre数组指的是上一个与p[i]一样大的位置对应的ans,也就是ans[pre[p[i]]]。

    当前的位置要比那个ans小1,而ans[i+1]也要比ans[i]小1。

    因为p[i]多出现了一次,所以上一个ans[pre[p[i]]要加1,这样就不会出现非正数。

    #include <bits/stdc++.h>
    using namespace std;
     
    int n,p[200005],pre[200005],a[200005];
     
    void solve()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",p+i);
            if(p[i]==-1) p[i]=p[i-1]+1;
            a[i]=0,pre[i]=i;
        }
        stack<int> q;
        for(int i=1;i<=n;i++)
        {
            int t=p[i-1]-p[i]+1;
            while(t--) pre[i]=min(pre[i],pre[q.top()]),q.pop();
            q.push(i);
            a[i]+=pre[i]-1,a[i+1]-=pre[i],a[pre[i]]++;
        }
        for(int i=1,t=0;i<=n;i++) t+=a[i],printf("%d ",t);
        printf("
    ");
    }
     
    int main()
    {
        int _;
        scanf("%d",&_);
        while(_--) solve();
        return 0;
    }
    View Code

    2. 用邻接表/链表模拟

    可以根据大小的相对次序来模拟,遍历邻接表就可以得到答案。

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn = 2e5+10;
    int T, n;
    int p[maxn], a[maxn];
    int tail, nxt[maxn], pre[maxn], lst[maxn];
    
    int main()
    {
        scanf("%d", &T);
        while(T--) {
            scanf("%d", &n);
            for(int i = 1; i <= n; i++) {
                scanf("%d", &p[i]);
                if(p[i] == -1) p[i] = p[i-1] + 1;
                nxt[i] = pre[i] = 0;
            }
            tail = 0;
            for(int i = 1; i <= n; i++) {
                if(p[i] > p[i-1]) {     //接在尾部
                    nxt[tail] = i;
                    pre[i] = tail;
                    tail = i;
                } else {                //接在上一个同样大小的的前面
                    int x = lst[p[i]];
                    nxt[pre[x]] = i;
                    pre[i] = pre[x];
                    nxt[i] = x;
                    pre[x] = i;
                }
                lst[p[i]] = i;
            }
            for(int i = 1, j = nxt[0]; i <= n; i++, j = nxt[j]) {
                a[j]  = i;
            }
            for(int i = 1; i <= n; i++)
                printf("%d ", a[i]);
            puts("");
        }    
        return 0;
    }
    View Code

    3. 用拓扑排序

    设每个位置的入度是大于p[i]的个数,则可通过拓扑排序得到答案。

    借助大根堆来模拟,这个时候是位置越靠后的ans[i]越大。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    #include<vector>
    #include<queue>
    #include<map>
    #include<cassert>
    #include<functional>
    #include<numeric>
    #include<set>
    #include<unordered_map>
    #include<tuple>
    #include<random>
    using namespace std;
    #define rep(i,l,r) for(int i=(l);i<=(r);++i)
    #define rpe(i,r,l) for(int i=(r);i>=(l);--i)
    #define rpp(i,x,e,head) for(int i=head[x];~i;i=e[i].next)
    #define dyes cerr<<"yes"<<endl
    #define dbg(x) cerr<<#x<<"="<<x<<endl
    #define debug(...) fprintf(stderr, __VA_ARGS__)
    #define pts puts("")
    typedef double db;
    typedef long long ll;
    typedef unsigned long long ull;
    inline int read(){
        int f=1,x=0;char ch;
        do{ch=getchar();if(ch=='-')f=-1LL;}while(ch<'0'||ch>'9');
        do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
        return f*x;
    }
    inline ll readll(){
        ll f=1,x=0;char ch;
        do{ch=getchar();if(ch=='-')f=-1LL;}while(ch<'0'||ch>'9');
        do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
        return f*x;
    }
    template <class T> inline void chmax(T &a,T b){if(a<b) a=b;}
    template <class T> inline void chmin(T &a,T b){if(a>b) a=b;}
    inline void swap(int &a,int &b){int c=a;a=b;b=c;}
    using namespace std;
    #define mst(a,val) memset(a,val,sizeof(a))
    #define pii pair<int,int>
    #define piii pair<int,pair<int,int> >
    #define mp(i,j) make_pair(i,j)
    #define fi first
    #define sc second
    #define inf (0x3f3f3f3f)
    #define infl (0x3f3f3f3f3f3f3f3fLL)
    #define forvec(i,j) for(vector<int>::iterator i=j.begin();i!=j.end();++i)
    #define forvecv(i,j) for(vector<int>::iterator i=--j.end();i>=j.begin();--i)
    //=====================head end======================//
    const int N=2e5+10;
    int n,a[N],pre[N],in[N],ans[N];
    vector<int> G[N];
    inline void wk(){
        n=read();rep(i,1,n) a[i]=read();
        rep(i,1,n) G[i].clear();
        rep(i,1,n) in[i]=0;
        rep(i,1,n) pre[i]=0;
        rep(i,1,n) if(a[i]==-1) a[i]=a[i-1]+1;
        rep(i,1,n){
            if(a[i]<=a[i-1])
                G[pre[a[i]]].emplace_back(i),++in[i];
            if(a[i]>1)
                G[i].emplace_back(pre[a[i]-1]),++in[pre[a[i]-1]];
            pre[a[i]]=i;
        }
        priority_queue<int> pq;
        rep(i,1,n) if(!in[i]) pq.emplace(i);
        int cur=n;
        while(!pq.empty()){
            int x=pq.top();pq.pop();
            ans[x]=cur;cur--;
            for(auto v:G[x]){
                --in[v];
                if(!in[v]) pq.emplace(v);
            }
        }
        rep(i,1,n) printf("%d%c",ans[i]," 
    "[i==n]);
    }
    int main(){
        int T=read();
        while(T--) wk();
        return 0;
    }
    View Code

    4. 用栈模拟大小次序,最后离散化得到答案

    如果p[i[比当前栈的大小还大,则直接添加。

    否则,ans[i]就是上一个和p[i]样大的位置对应的ans-1,并更新栈大小为当前ans[i]。

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    int n, a[1000005], top;
    int b[1000005], ans[1000005], srt[1000005], mx;
     
    signed main() {
        int t;
        cin>>t;
        while(t--){
            cin>>n;
            for (int i = 1; i <= n; i++) {
                cin>>a[i];
                ans[i]=0;
                b[i]=0;
                srt[i]=0;
            }
            int top=0;
            int mx=0;
            for (int i = 1; i <= n; i++) {
                if (a[i] == -1) {
                    ans[i] = i * 1000005;
                    b[++top] = ans[i];
                } else {
                    if (a[i] > top) {
                        ans[i] = i * 1000005;
                        b[++top] = ans[i];
                    } else {
                        ans[i] = b[a[i]] - 1;
                        b[top = a[i]] = ans[i];
                    }
                }
            }
            for (int i = 1; i <= n; i++) srt[i] = ans[i];
            sort(srt + 1, srt + n + 1);
            for (int i = 1; i <= n; i++) ans[i] = lower_bound(srt + 1, srt + n + 1, ans[i]) - srt;
            for (int i = 1; i <= n; i++) cout<<ans[i]<<" ";
            cout<<endl;
        }
        return 0;
    }
    View Code

    5. 用dfs,根据p[i]的值一层层处理。

    首先将对应p[i]位置存起来,然后根据题解描述,找出分段,并递归处理分段。

    分段的区间可以通过二分找到,不用再遍历了。

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn = 1e5+10;
    int t, n, num, top;
    int a[maxn], b[maxn], sta[maxn];
    vector<int> v[maxn];
    void dfs(int pos, int l, int r) {
        // printf("%d %d %d %d
    ", pos, num, l, r);
        if(l > r || v[pos].size() == 0) {
            return ;
        }
        int st = lower_bound(v[pos].begin(), v[pos].end(), l) - v[pos].begin();
        int ed = lower_bound(v[pos].begin(), v[pos].end(), r) - v[pos].begin();
        /*printf("%d %d %d
    ", pos, st, ed);
        for(int i = 0; i < (int)v[pos].size(); i++)
            printf("%d ", v[pos][i]);
        puts("");*/
        if(st >= ed) return ;
        b[v[pos][ed-1]] = num++;
        for(int i = ed-2; i >= st; i--) {
            b[v[pos][i]] = num++;
        }
        dfs(pos+1, l, v[pos][st]);
        for(int i = st; i < ed-1; i++) {
            dfs(pos+1, v[pos][i], v[pos][i+1]);
        }
        dfs(pos+1, v[pos][ed-1], r);
    }
    int main()
    {
        scanf("%d", &t);
        while(t--) {
            scanf("%d", &n);
            for(int i = 1; i <= n; i++) {
                scanf("%d", &a[i]);
                if(a[i] == -1) a[i] = a[i-1]+1;
                v[a[i]].push_back(i);
            }
            /*for(int i = 1; i <= n; i++) {
                for(int j = 0; j < (int)v[i].size(); j++)
                    printf("%d ", v[i][j]);
                puts("");
            }*/
            num = 1;
            dfs(1, 0, n+1);
            for(int i = 1; i <= n; i++)
                printf("%d ", b[i]);
            puts("");
            /*top = 0;
            for(int i = 1; i <= n; i++) {
                while(top > 0 && sta[top] > b[i]) top--;
                sta[++top] = b[i];
                printf("%d ", top);
            }
            puts("");*/
            for(int i = 1; i <= n; i++) v[i].clear();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    20155208徐子涵 2016-2017-2 《Java程序设计》第8周学习总结
    20155208徐子涵 2016-2017-2 《Java程序设计》第7周学习总结
    20155208徐子涵 2016-2017-2 《Java程序设计》第6周学习总结
    20155208徐子涵 2016-2017-2 《Java程序设计》第5周学习总结
    20155208徐子涵 2016-2017-2 《Java程序设计》第4周学习总结
    20155208徐子涵 2016-2017-2 《Java程序设计》第3周学习总结
    20155208徐子涵 2016-2017-2 《Java程序设计》第2周学习总结
    20155207 2016-2017-2 《Java程序设计》第十周学习总结
    20155207 2016-2017-2 《Java程序设计》第九周学习总结
    20155207 2016-2017-2 《Java程序设计》第八周学习总结
  • 原文地址:https://www.cnblogs.com/canchan/p/12741337.html
Copyright © 2011-2022 走看看