• 【题解】毒瘤 OI 刷题汇总 [SCOI2016]


    【题解】毒瘤 OI 刷题汇总 [SCOI2016]


    【Day1 T1】背单词

    传送门:背单词 ( ext{[P3294]}) ( ext{[Bzoj4567]})

    【题目描述】

    给你一些字符串,让你对其进行排列,要求满足以下规则,求最少花费
    (x) 为字符串在自行排定的序列中的位置,当前字符串为 (a))

    • 如果 (a) 存在后缀且 (a) 的后缀在 (a) 之后,则花费 (n^2)

    • 如果 (a) 不存在后缀则花费 (x)

    • (a) 存在后缀且 (a) 的后缀在 (a) 之前,设 (y)(a) 之前离其最近的是 (a) 的后缀的字符串的位置,则花费 (x−y)

    【分析】

    这题极其诡异,小菜鸡很难讲清楚,干脆挂一下 ( ext{Tian_Xing}) 神仙的博客链接好了 【这是一个链接】

    【Code】

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<string>
    #include<vector>
    #include<map>
    #define LL long long
    #define Re register int
    #define IT vector<int>::iterator
    using namespace std;
    const int N=1e5+5,M=510003;
    int n,o;LL ans;char ch[M];map<string,int>ID;
    vector<int>to[N];
    inline void add(Re x,Re y){to[x].push_back(y);}
    inline void in(Re &x){
        int f=0;x=0;char c=getchar();
        while(c<'0'||c>'9')f|=c=='-',c=getchar();
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
        x=f?-x:x;
    }
    int O=1,now,id[N],fa[M*26],ed[M*26],size[N],tr[M*26][26];
    inline int find(Re x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    inline void insert(char ch[],Re n,Re id){
        Re p=1;
        for(Re i=1;i<=n;++i){
            Re a=ch[i]-'a';
            if(!tr[p][a])tr[p][a]=++O;
            p=tr[p][a];
        }
        ed[p]=id+1;
    }
    inline bool cmp(Re x,Re y){return size[x]<size[y];}
    inline void build(Re x){
        for(Re i=0;i<26;++i)
            if(tr[x][i]){
                if(ed[tr[x][i]])add(ed[find(x)],ed[fa[tr[x][i]]=tr[x][i]]);
                else fa[tr[x][i]]=find(x);
                build(tr[x][i]);
            }
    }
    inline void dfs(Re x){
        size[x]=1;
        for(IT i=to[x].begin();i!=to[x].end();++i)dfs(*i),size[x]+=size[*i];
        sort(to[x].begin(),to[x].end(),cmp);
    }
    inline void dfs_(Re x,Re fa){
        ans+=(id[x]-fa);
        for(IT i=to[x].begin();i!=to[x].end();++i)id[*i]=++now,dfs_(*i,id[x]);
    }
    int main(){
    //    freopen("word.in","r",stdin);
    //    freopen("word.out","w",stdout);
        in(n);
        for(Re i=1;i<=n;++i){
            scanf("%s",ch+1);Re m=strlen(ch+1);
            for(Re j=1;j<=m/2;++j)swap(ch[j],ch[m-j+1]);
            insert(ch,m,i);
        }
        ed[fa[1]=1]=1,build(1),dfs(1),dfs_(1,0);
        printf("%lld
    ",ans);
        fclose(stdin);
        fclose(stdout);
    }
    

    【Day1 T2】幸运数字

    传送门:幸运数字 ( ext{[P3292]}) ( ext{[Bzoj4568]})

    【题目描述】

    给出一颗 (n) ((nleqslant 2*10^4)) 个点的树,多次询问树上两点之间的路径上最大点权异或和。

    【分析】

    暴力倍增线性基合并。

    考虑在倍增求 (LCA) 时同时维护线性基,即用 (f[x][j]) 储存点 (x) 到它的 (2^j) 级祖先处的路径上的所有点所组成的线性基信息。

    对于每次询问,在往上跳跃时顺便把路径上的各个线性基合并起来,最后查询最大值即可。

    时间复杂度:(O(nlog^3 n))

    (把倍增换成树剖貌似常数要小一些)

    【Code】

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #define LL long long
    #define Re register LL
    using namespace std;
    const LL N=2e4+3,M=2e5+3,inf=2e18,logN=14;
    LL n,m,o,x,y,T,A[N],head[N];
    struct QAQ{LL to,next;}a[N<<1];
    inline void add(Re x,Re y){a[++o].to=y,a[o].next=head[x],head[x]=o;}
    inline void in(Re &x){
        int f=0;x=0;char c=getchar();
        while(c<'0'||c>'9')f|=c=='-',c=getchar();
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
        x=f?-x:x;
    }
    struct JI{
        LL p[61];JI(){memset(p,0,sizeof(p));}
        inline void insert(Re x){
            for(Re i=60;i>=0;--i)
                if((x>>i)&1){
                    if(!p[i]){p[i]=x;break;}
                    x^=p[i];
                }
        }
        inline void merge(JI O){
            for(Re i=60;i>=0;--i)if(O.p[i])insert(O.p[i]);
        }
        inline LL ask(){
            Re ans=0;
            for(Re i=60;i>=0;--i)ans=max(ans,ans^p[i]);
            return ans;
        }
    };
    struct LCA{
        LL deep[N],fa[N][15],ant[N][15];JI dp[N][15];
        inline void dfs(Re x,Re fa){
            deep[x]=deep[ant[x][0]=fa]+1,dp[x][0].insert(A[fa]);
            for(Re j=1;(1<<j)<=deep[x];++j)ant[x][j]=ant[ant[x][j-1]][j-1],dp[x][j]=dp[x][j-1],dp[x][j].merge(dp[ant[x][j-1]][j-1]);
            for(Re i=head[x];i;i=a[i].next)if(a[i].to!=fa)dfs(a[i].to,x);
        }
        inline JI ask(Re x,Re y){
            JI Ans;Ans.insert(A[x]),Ans.insert(A[y]);
            if(deep[x]<deep[y])swap(x,y);
            for(Re i=logN;i>=0;--i)if(deep[ant[x][i]]>=deep[y])Ans.merge(dp[x][i]),x=ant[x][i];
            if(x==y)return Ans;
            for(Re i=logN;i>=0;--i)if(ant[x][i]!=ant[y][i])Ans.merge(dp[x][i]),Ans.merge(dp[y][i]),x=ant[x][i],y=ant[y][i];
            Ans.merge(dp[x][0]);
            return Ans;
        }
    }T1;
    int main(){
    //    freopen("lucky.in","r",stdin);
    //    freopen("lucky.out","w",stdout);
        in(n),in(T),m=n-1;
        for(Re i=1;i<=n;++i)in(A[i]);
        while(m--)in(x),in(y),add(x,y),add(y,x);
        T1.dfs(1,0);
        while(T--)in(x),in(y),printf("%lld
    ",T1.ask(x,y).ask());
    }
    

    【Day1 T3】萌萌哒

    传送门:萌萌哒 ( ext{[P3295]}) ( ext{[Bzoj4569]})

    【题目描述】

    你需要构造一个长为 (n) ((nleqslant 10^5)) 的数 (S),给出 (m) ((mleqslant 10^5)) 个限制条件,每个限制条件包含四个整数 (l_1,r_1,l_2,r_2),表示 (S_{l_1}S_{l_1+1}...S_{r_1})(S_{l_2}S_{l_2+1}...S_{r_2}) 必须完全相同。求合法 (S) 的个数。

    【分析】

    神奇的倍增优化冰茶姬。

    有一个很 (naive) 的想法:冰茶姬暴力枚举连边,最后求出不同联通块的个数 (cnt),则答案为 (9*10^{cnt})

    考虑用倍增进行优化,用 (fa[x][j]) 表示区间 ([x,x+2^j-1]) 与其他点的关系,对于每个限制条件把给出区间分为 (log) 部分依次连边,最后再依次根据长为 (2^j) 的大区间连通块信息 对长度为 (2^{j-1}) 的小区间进行合并。有点类似于打懒标记和最后标记的下放(或者说和线段树优化建边比较像?)。

    时间复杂度:(O(nlog n))(带一个冰茶姬的常数)。

    【Code】

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #define LL long long
    #define Re register int
    using namespace std;
    const int N=1e5+3,logN=17,P=1e9+7;
    int n,a,b,c,d,T,cnt=-1,fa[N][20];LL ans=9;
    inline void in(Re &x){
        Re f=0;x=0;char c=getchar();
        while(c<'0'||c>'9')f|=c=='-',c=getchar();
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
        x=f?-x:x;
    }
    inline int find(Re x,Re k){return fa[x][k]==x?x:fa[x][k]=find(fa[x][k],k);}
    inline void merge(Re x,Re y,Re k){if((x=find(x,k))!=(y=find(y,k)))fa[x][k]=y;}
    int main(){
    //    freopen("123.txt","r",stdin);
        in(n),in(T);
        for(Re j=0;j<=logN;++j)
            for(Re i=1;i<=n;++i)
                fa[i][j]=i;
        while(T--){
            in(a),in(b),in(c),in(d);
            for(Re j=logN;j>=0;--j)if(a+(1<<j)-1<=b)merge(a,c,j),a+=(1<<j),c+=(1<<j);
        }
        for(Re j=logN;j>=1;--j)
            for(Re i=1;i+(1<<j)-1<=n;++i)
                merge(i,find(i,j),j-1),merge(i+(1<<j-1),find(i,j)+(1<<j-1),j-1);
        for(Re i=1;i<=n;++i)if(find(i,0)==i)++cnt;
        while(cnt--)(ans*=10)%=P;
        printf("%lld
    ",ans);
    }
    

    【Day2 T1】妖怪

    传送门:妖怪 ( ext{[P3291]}) ( ext{[Bzoj4570]})

    【题目描述】

    给出 (n) ((nleqslant 10^6)) 个点 ((x_i,y_i)),设 (f_i(a,b)=x_i+y_i+frac{bx_i}{a}+frac{ay_i}{b}),求出一组 ((a,b)),使得 (max{f_{iin[1,n]}(a,b)}) 最小,输出这个最小值。

    【分析】

    【题解】妖怪 ( ext{[SCOI2016] [P3291] [Bzoj4570]})

    【Code】

    不知道这儿能放啥,干脆买个萌吧(⊙ω⊙)
    

    【Day2 T2】美味

    传送门:美味 ( ext{[P3293]}) ( ext{[Bzoj4571]})

    【题目描述】

    给出一个长为 (n) ((nleqslant 2*10^5)) 的序列 (a) ((0leqslant a_i< 10^5)),有 (m) ((mleqslant 10^5)) 次询问,每次询问给出四个整数 (b x l r),在区间 ([l,r]) 中寻找一个 (i) 使得 (b operatorname{xor} (a_i+x)) 最大,并输出这个这个最大值。

    【分析】

    暴力枚举+主席树瞎搞。

    首先肯定是要从高位到低位依次枚举,每次贪心选对应位上与 (b) 不同的(异或起来尽量大)。设当前所选出的 (a_i+x) 只取前 (i-1) 位时等于 (now),则要想使得 (now) 的第 (i) 位为 (1) 就必须满足存在一个 (i) 使得 (now-xleqslant a_i leqslant (now|(1<<i))-x-1),要想为 (0) 必须满足存在一个 (i) 使得 ((now|(1<<i))-xleqslant a_ileqslant (now|(1<<i+1))-x-1) 。建一颗主席树,每次查询 ([l,r]) 内满足要求的 (i) 的个数即可。

    时间复杂度:(O(nlog inf+mlog^2 inf))

    【Code】

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #define LL long long
    #define Re register int
    using namespace std;
    const int N=2e5+5,M=1e5+3,logM=17;
    int n,m,b,x,l,r,T,A[N];
    inline void in(Re &x){
        int f=0;x=0;char c=getchar();
        while(c<'0'||c>'9')f|=c=='-',c=getchar();
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
        x=f?-x:x;
    }
    int pt[N];
    struct Segment_Tree{
        #define pl (tr[p].lp)
        #define pr (tr[p].rp)
        #define mid ((L+R)>>1)
        int O;
        struct QAQ{int S,lp,rp;}tr[N*logM<<1];
        inline void creat(Re &p,Re q,Re L,Re R,Re x){
            tr[p=++O]=tr[q],++tr[p].S;
            if(L==R)return;
            if(x<=mid)creat(pl,tr[q].lp,L,mid,x);
            else creat(pr,tr[q].rp,mid+1,R,x);
        }
        inline int ask(Re p,Re q,Re L,Re R,Re l,Re r){
            if(!p&&!q)return 0;
            if(l<=L&&R<=r)return tr[p].S-tr[q].S;
            Re ans=0;
            if(l<=mid)ans+=ask(pl,tr[q].lp,L,mid,l,r);
            if(r>mid)ans+=ask(pr,tr[q].rp,mid+1,R,l,r);
            return ans;
        }
    }TR;
    int main(){
    //    freopen("123.txt","r",stdin);
        in(n),in(T);
        for(Re i=1;i<=n;++i)in(A[i]),m=max(m,A[i]);
        for(Re i=1;i<=n;++i)TR.creat(pt[i],pt[i-1],0,m,A[i]);
        while(T--){
            in(b),in(x),in(l),in(r);Re now=0;
            for(Re i=logM;i>=0;--i)
                if((b>>i)&1){
                    if(TR.ask(pt[r],pt[l-1],0,m,now-x,now+(1<<i)-x-1));//取o^1=0
                    else now|=1<<i;//取o=1 
                }
                else{
                    if(TR.ask(pt[r],pt[l-1],0,m,now+(1<<i)-x,now+(1<<i+1)-x-1))now|=1<<i;//取o^1=1 
                    else;//取o=0 
                }
            printf("%d
    ",now^b);
        }
    }
    

    【Day2 T3】围棋

    传送门:围棋 ( ext{[P3290]}) ( ext{[Bzoj4572]})

    【题目描述】

    略。

    【分析】

    又双叒叕是一道毒瘤插头 (dp),不会,咕掉。

    【Code】

    不知道这儿能放啥,干脆买个萌吧(⊙ω⊙)
    

  • 相关阅读:
    bootstrap中的动态加载出来的图片轮播中的li标签中的class="active"的动态添加移除
    细碎的小定义的记录
    jQuery动态添加的元素中处理字符串溢出后在指定字符数后添加省略号
    ASP.NET中扩展FileUpload的上传文件的容量
    SVN错误:Attempted to lock an already-locked dir
    Eclipse中jsp、js文件编辑时,卡死现象解决汇总(转)
    修改weblogic端口的方法
    oracle 使用触发器实现id自增
    nui UI 具有右键属性的菜单树
    eclipse中 将java项目转换为web项目
  • 原文地址:https://www.cnblogs.com/Xing-Ling/p/12763384.html
Copyright © 2020-2023  润新知