zoukankan      html  css  js  c++  java
  • 平时十八测

    今天没有一道题想到正解,全部打的暴力,今天题思维很活啊;

    第一题:主要是利用只有26个字母,往这方面想了,但失败了;

    计数排序:主要针对数据很集中的;

    建26棵线段树,记录区间中该数有多少个,每次查询区间中26个字母各有多少个,按顺序排列;就一个区间查询,修改操作,此题卡常;

    #include<bits/stdc++.h>
    using namespace std;
    
    const int M = 1e5 + 5;
    char s[M];
    int f[M][27], n, m, cnt[27];
    int read(){
        int x = 0; int f = 1; char c = getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c<='9'&&c>='0'){x=x*10+c-'0';c=getchar();}
        return x*=f;
    }
    #define For(a, b, c) for(int a = b; a <= c; a++)
    struct Node{
        int v, tag; 
        Node *ls, *rs;
        void up(){
            v = ls->v + rs->v;
        }
        void down(int lf, int rg){
            if(tag != -1){
                int mid = (lf + rg) >> 1;
                ls->tag = rs->tag = tag;
                ls->v = (mid - lf + 1) * tag;
                rs->v = (rg - mid) * tag;
                tag = -1;
            }
        }
        
    }pool[(M * 27 )<< 2], *root[27], *tail = pool;
    #define Ls nd->ls, lf, mid
    #define Rs nd->rs, mid+1, rg 
    Node *build(int d, int lf = 1, int rg = n){
        Node *nd = ++tail;
        nd->tag = -1;
        if(lf == rg)nd->v = f[lf][d];
        else {
            int mid = (lf + rg) >> 1;
            nd->ls = build(d, lf, mid);
            nd->rs = build(d, mid+1, rg);
            nd->up();
        }
        return nd;
    }
    void del(int L, int R, Node *nd, int lf = 1, int rg = n){
        if(L <= lf && rg <= R){
            nd->v = rg - lf + 1;
            nd->tag = 1;
        }
        else {
            nd->down(lf, rg);
            int mid = (lf + rg) >> 1;
            if(L <= mid)del(L, R, Ls);
            if(R > mid) del(L, R, Rs);
            nd->up();
        }
        return ;
    }
    int query(int L, int R, Node *nd, int lf = 1, int rg = n){
        if(nd->v == 0)return 0;
        if(L <= lf && rg <= R){
            int c = nd->v;
            nd->v = 0; 
            nd->tag = 0;
            return c;
        }
        int mid = (lf + rg) >> 1;
        nd->down(lf, rg);
        int ans = 0;
        if(L <= mid) ans += query(L, R, Ls);
        if(R > mid) ans += query(L, R, Rs);
        nd->up();
        return ans;
    }
    
    
    int main(){
    //    
        freopen("string.in","r",stdin);
        freopen("string.out","w",stdout);
        n = read(), m = read();
        int t = 0;
        char c = getchar();
        while(c<'a'||c>'z')c=getchar();
        while(c!='
    '){f[++t][c-'a'+1]=1;c=getchar();}
        For(i, 1, 26) root[i] = build(i);
        while(m--){
            int l = read(), r = read(), opt = read();
            For(i, 1, 26) cnt[i] = query(l, r, root[i]);
            int ed = l;
            if(opt) {
                For(i, 1, 26)
                if(cnt[i]) {
                    del(ed, ed + cnt[i] - 1, root[i]);
                    ed = ed + cnt[i];
                }
            }
            else {
                for(int i = 26; i; i--)
                if(cnt[i]) {
                    del(ed, ed + cnt[i] - 1, root[i]);
                    ed = ed + cnt[i];
                }
            }
        }
        For(i, 1, n)
            For(j, 1, 26)
                if(query(i, i, root[j])) putchar('a'+j-1);
        putchar('
    ');
    }
    View Code

    第二题:神奇的DP;

    dp[i][j] 表示考虑到前i列,满足右区间的放了j个的方案数;sl, sr,是对左右区间记录的前缀和

    这个转移=左方案*右方案;越过一个左侧区间的右端点时,从之前剩下的空列中选一列在这个左侧区间放1。转移时分在右侧区间放1或不放1;

    考虑右边:可以不放dp[i-1][j], 也可以放f[i-1][j-1] * (sr[i] - (j-1));

    考虑左边:对于每个在sl[i-1]到sl[i]的行枚举右边放了j个, 则有 (i - j - k) (k = sl[i-1] ~ sl[i] - 1) 位置可以选择;

    #include<bits/stdc++.h>
    using namespace std;
    #define RG register
    const int M = 3005;
    #define ll long long
    const ll mod=998244353;
    ll f[M][M]; int sl[M], sr[M];
    
    int main(){
        freopen("matrix.in","r",stdin);
        freopen("matrix.out","w",stdout);
        int l, r, n, m;
        scanf("%d%d
    ", &n, &m);
        for(int i=1;i<=n;i++){
            scanf("%d%d", &l, &r);
            sl[l]++, sr[r]++;
        }
        for(int i = 1; i <= m; i++) sl[i] += sl[i - 1], sr[i] += sr[i - 1];
        f[0][0] = 1;
        for(int i = 1; i <= m; i++){
            f[i][0] = f[i - 1][0];
            for(int j = 1; j <= i; j++)
                f[i][j] = (f[i - 1][j] + f[i - 1][j - 1] * (sr[i] - j + 1)) % mod;
            for(int k = sl[i-1]; k < sl[i]; k++)
                for(int j = 0; j < i; j++){
                    f[i][j] = f[i][j] * (i - j - k) % mod;
                }
        }
        printf("%lld
    ", f[m][n]);
        
        
        return 0;
    }
    View Code

    第三题:Trie树;

    对手做的是将x在二进制下左移一位。假设在异或i个数后左移,等价于开始时先左移,然后把前i个数左移一位。(这道题其他都想到了,就是这个没想到)
    问题转化为选一个数,使它左移一位后,与m+1个给定数分别异或的最小值最大。将m+1个数建立一棵字典树,从上到下遍历来最大化结果:

    走到一个点时,如果往下只有0,说明我们这一位取1异或后只能是1,累计结果中加上这一位的值,只有1也一样;如果既有0又有1,说明这一位无论怎么取最后都是0,分别往下走即可。

    时间复杂度O(nm)。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int M = 1e5 + 5, ME = 5e6;
    int a[M], pre[M], lst[M], bin[32], c[M];
    int ch[ME][2];
    int ans , cnt, tot, up, n;
    void insert(int x){
        int now = 0;
        for(int i = n-1; i >= 0; i--){
            int t = x & bin[i] ? 1 : 0;
            if(!ch[now][t]) ch[now][t] = ++tot;
            now = ch[now][t];
        }
    }
    void dfs(int now, int dep, int val){
        if(dep==-1){
            if(val > ans) ans = val, cnt = 1;
            else if(val == ans) cnt ++;
            return ;
        }
        if(ch[now][0] && ch[now][1]){
            dfs(ch[now][0], dep-1, val);
            dfs(ch[now][1], dep-1, val);
        }
        else if(ch[now][1]){
            dfs(ch[now][1], dep-1, val+bin[dep]);
        } 
        else {
            dfs(ch[now][0], dep-1, val+bin[dep]);
        }
    }
    
    int main(){
        freopen("big.in","r",stdin);
        freopen("big.out","w",stdout);
        int m;
        scanf("%d%d", &n, &m);
        bin[0] = 1;
        for(int i = 1; i <= 30; i++) bin[i] = bin[i-1]<<1;
        for(int i = 1; i <= m; i++){
            scanf("%d", &a[i]);
            pre[i] = pre[i-1]^a[i];
        }
        up = 1<<n;
        for(int i = m; i; i--)lst[i] = lst[i+1]^a[i];
        for(int i = 0; i <= m; i++){
            int t = (long long)(pre[i]<<1)/up;
            c[i] = ((long long)(pre[i]<<1)&(up-1))+t;
            c[i] ^= lst[i+1];
            insert(c[i]);
        }
        dfs(0, n-1, 0);
        printf("%d
    %d
    ", ans, cnt);
    }
    View Code
  • 相关阅读:
    ODI ORA-00932: 数据类型不一致: 应为 -, 但却获得 CLOB
    oracle 执行计划简介
    oracle job定时执行存储过程详解
    ODI 目标表主键有序列的同步处理
    ODI 同义词问题
    U盘安装redhat Linux
    ODI ora_01653 表空间无法扩展
    C#使用JSON相关
    常用查询汇总
    EXCEL中汉字转拼音
  • 原文地址:https://www.cnblogs.com/EdSheeran/p/9871846.html
Copyright © 2011-2022 走看看