zoukankan      html  css  js  c++  java
  • NOIP模拟测试on 2019.9.27

    T1 string

    面对1e5的数据范围,暴力sort肯定不行,而我一开始连sort都能写错,真是傻逼到了极点。

    考虑用线段树维护,我们看题目中只有26个小写字母,就可以维护每个区间对应的字母,修改时就做26次区间赋值操作。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+7;
    struct node{
        int l,r,v;
    }tree[maxn*4];
    char str[maxn];
    int n,m,l,r,opt;
    int f[maxn];//一个区间中'a'-'z'字母的个数 
    void ljb(){
        freopen("string.in","r",stdin);
        freopen("string.out","w",stdout);
    }
    void build(int now,int l,int r){
        tree[now].l=l,tree[now].r=r;
        if(l==r){
            tree[now].v=str[l]-'a'+1;
            return;
        } 
        int mid=(l+r)>>1;
        build(now<<1,l,mid);
        build(now<<1|1,mid+1,r);
        if(tree[now<<1].v==tree[now<<1|1].v) tree[now].v=tree[now<<1].v;
    }
    void update(int now,int l,int r){
        if(tree[now].l>=l&&tree[now].r<=r&&tree[now].v){
            f[tree[now].v]+=tree[now].r-tree[now].l+1;
            return;
        }
        if(tree[now].v) tree[now<<1].v=tree[now<<1|1].v=tree[now].v;
        int mid=(tree[now].l+tree[now].r)>>1;
        if(l<=mid) update(now<<1,l,r);
        if(r>mid) update(now<<1|1,l,r);
    }
    void modify(int now,int l,int r,int x){
        if(tree[now].l>=l&&tree[now].r<=r||tree[now].v==x){
            tree[now].v=x;
            return;
        }
        if(tree[now].v) tree[now<<1].v=tree[now].v,tree[now<<1|1].v=tree[now].v,tree[now].v=0;
        int mid=(tree[now].l+tree[now].r)>>1;
        if(l<=mid) modify(now<<1,l,r,x);
        if(r>mid) modify(now<<1|1,l,r,x);
        if(tree[now<<1].v==tree[now<<1|1].v) tree[now].v=tree[now<<1].v;
    }
    void print(int now){
        if(tree[now].v){
            for(int i=tree[now].l;i<=tree[now].r;i++) printf("%c",tree[now].v+'a'-1);
            return;
        }
        print(now<<1);print(now<<1|1);
    }
    int main(){
        ljb();
        scanf("%d%d",&n,&m);
        scanf("%s",str+1);    
        build(1,1,n);
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&l,&r,&opt);
            for(int j=1;j<=28;j++) f[j]=0;
            update(1,l,r);
            if(opt){
                for(int j=1;j<=26;j++){
                    if(f[j]){
                        modify(1,l,l+f[j]-1,j);
                        l+=f[j];
                    }
                }  
            }
            else{
                for(int j=26;j>=1;j--){
                    if(f[j]){
                        modify(1,l,l+f[j]-1,j);
                        l+=f[j];
                    }
                }
            } 
        }
        print(1);
        return 0;
    } 
    View Code

    T2 matrix

    神仙dp。只能%%%tqr

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+7;
    const int N=5505;
    const int mod=998244353;
    int c[N][N];
    int x,y;
    int n,m;
    void pre(){
        c[0][0]=1;
        for(int i=1;i<=m;i++){
            c[i][0]=1;
            for(int j=1;j<=i;j++) c[i][j]=(1LL*c[i][j-1]*(i-j+1))%mod;
        }
    }
    int l[maxn],r[maxn];
    int f[N][N];
    void dp(){
        f[1][0]=1;
        for(int i=1;i<=m;i++){
            for(int j=0;j<=r[i];j++){
                if(i-j<l[i]) break;
                f[i][j]=1LL*f[i][j]*c[i-j-l[i-1]][l[i]-l[i-1]]%mod;
                f[i+1][j]=(f[i+1][j]+f[i][j])%mod;
                f[i+1][j+1]=(f[i+1][j+1]+1LL*f[i][j]*(r[i+1]-j)%mod)%mod;
            }
        }
        cout<<f[m][n];
    }
    int main(){
        freopen("matrix.in","r",stdin);
        freopen("matrix.out","w",stdout);
        scanf("%d%d",&n,&m);
        pre();
        for(int i=1;i<=n;i++){
            scanf("%d%d",&x,&y);
            l[x]++;r[y]++;
        }
        for(int i=1;i<=m;i++){
            l[i]+=l[i-1];
            r[i]+=r[i-1];
        }
        dp();
        return 0;
    }
    View Code

    T3 big

    暴力很好想,用前缀和可以减少一个n的复杂度。

    关键是题目中的那个式子如何转化,就是前移n位然后把之前的位补到后面,不知道这样解释对不对??:

    正解是在trie树上贪心的dfs,以后看到异或,还是可以往trie树上想一想。

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+7;
    int a[maxn];//原来的数组
    int suf[maxn];//后缀xor和
    int b[maxn];//改变之后的和
    int n,m; 
    int change(int x){
        return (((x<<1)/(1<<n))+(x<<1))%(1<<n);
    }
    int tr[maxn*2][2];
    int rt=1;
    int tot;
    void trie(int x){
        int rt=0;
        for(int i=n-1;i>=0;i--){
            int cur=(x>>i)&1;//取出当前位
            if(!tr[rt][cur]) tr[rt][cur]=++tot;
            rt=tr[rt][cur]; 
        }
    }
    int maxx,cnt;
    void dfs(int now,int dep,int ans){
        if(dep==-1){
            if(ans>maxx){
                maxx=ans;
                cnt=1;
            }
            else if(ans==maxx) cnt++;
            return;
        }
        if(tr[now][0]&&tr[now][1]){
            dfs(tr[now][0],dep-1,ans);
            dfs(tr[now][1],dep-1,ans);
        } 
        else if(tr[now][1]!=0) dfs(tr[now][1],dep-1,ans+(1<<dep));
        else dfs(tr[now][0],dep-1,ans+(1<<dep));
    }
    int main(){
        freopen("big.in","r",stdin);
        freopen("big.out","w",stdout);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++) scanf("%d",&a[i]);
        for(int i=m;i>=0;i--) suf[i]=suf[i+1]^a[i];
        for(int i=0;i<=m;i++){
            a[i]=a[i]^a[i-1];
            b[i]=change(a[i]);
        }
        for(int i=0;i<=m;i++) b[i]=b[i]^suf[i+1];
        for(int i=0;i<=m;i++) trie(b[i]);
        dfs(0,n-1,0);
        printf("%d
    %d
    ",maxx,cnt);
        return 0;
    } 
    View Code
  • 相关阅读:
    SPOJ SAMER08A
    SPOJ TRAFFICN
    CS Academy Set Subtraction
    CS Academy Bad Triplet
    CF Round 432 C. Five Dimensional Points
    CF Round 432 B. Arpa and an exam about geometry
    SPOJ INVCNT
    CS Academy Palindromic Tree
    身体训练
    简单瞎搞题
  • 原文地址:https://www.cnblogs.com/LJB666/p/11614654.html
Copyright © 2011-2022 走看看