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
  • 相关阅读:
    周学习笔记(04)——大三下
    进度(3)
    进度(2)
    进度(1)
    周学习笔记(03)——大三下
    《信息领域热词分析》之在代码层实现可用性战术
    周学习笔记(02)——大三下
    cf1041E
    cf1067b
    cf1131D
  • 原文地址:https://www.cnblogs.com/LJB666/p/11614654.html
Copyright © 2011-2022 走看看