zoukankan      html  css  js  c++  java
  • NOI2014 部分题解

    感觉NOI2014的一些题目也是比较好做的...

    但是笔者往往有思路却没有想清楚就开始搞了...这样还是不太好..

     

    Day1

    T1 起床困难综合征  (我感觉这题应该叫综合征不是综合症...)   ac通道

    让你从[0...m]中选一个数使得其经过 (&xi或|xi或^xi) 之后的值最大。

    记得冬令营有道试机题好像就是这样吧...然后机智的TB感觉十分自然的就想到了根据二进制的每一位来贪心弄一下就好了。

    大致思路就是:从最高位开始,看一下这一位设为0和设为1有什么区别。

    如果不管你设什么这一位运算完之后都为0或者为1,那就真·不管了...

    如果发现设为1有值而设为0没有值,那就设为1吧。但是这个值不能超过m...

    很机智的样子。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
     
    using namespace std;
     
    inline int in(){
        int x=0;char ch=getchar();
        while(ch>'9' || ch<'0') ch=getchar();
        while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
        return x;
    }
     
    const int maxn=100010;
     
    struct Node{
        int tp,dt;
    }s[maxn];
     
    int n,m;
    char ord[4];
     
    int calcu(int x){
        int tx=x; x=1<<x;
        for(int i=1;i<=n;i++){
            if(s[i].tp==1) x=x&s[i].dt;
            else if(s[i].tp==2) x=x|s[i].dt;
            else x=x^s[i].dt;
        }
        return x&(1<<tx);
    }
     
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("sleep.in","r",stdin);
        freopen("sleep.out","w",stdout);
    #endif
     
        n=in(),m=in();
        for(int i=1;i<=n;i++){
            scanf("%s%d",ord,&s[i].dt);
            if(ord[0]=='A') s[i].tp=1;
            else if(ord[0]=='O') s[i].tp=2;
            else s[i].tp=3;
        }
         
        int ans=0;
         
        int tmp=0;
        for(int i=1;i<=n;i++){
            if(s[i].tp==1) tmp=tmp&s[i].dt;
            else if(s[i].tp==2) tmp=tmp|s[i].dt;
            else tmp=tmp^s[i].dt;
        }
        for(int i=30;i>=0;i--){
            if(tmp & (1<<i)){
                ans+=1<<i; continue;
            }
            if(calcu(i) && m>(1<<i))
                ans+=1<<i,m-=(1<<i);
        }
         
        printf("%d",ans);
        return 0;
    }
    View Code



    T2 魔法森林 ac通道

    给你n个点m条边,每条边有2个权值,然后要求找一条路从1到n使得这条路上的两个权值的最大值加起来最小。

    我记得写过一篇题解的...

    然后就是复习一遍LCT的实现咯。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
     
    using namespace std;
     
    inline int in(){
        int x=0;char ch=getchar();
        while(ch>'9' || ch<'0') ch=getchar();
        while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
        return x;
    }
     
    const int maxn=100010;
     
    struct Node{
        int l,r,f;
        int dt,mx,lc;
        bool rt,rv;
        Node(){rt=true;}
        void trans(){swap(l,r);}
    }s[maxn*3];
     
    struct Edge{
        int u,v,a,b;
    }e[maxn];
     
    bool cmp(const Edge &A,const Edge &B){
        if(A.a!=B.a) return A.a<B.a; return A.b<B.b;
    }
     
    int n,m;
    int p[maxn*2];
     
    void update(int x);
    void push_down(int x);
    void Down_tag(int x);
    void zig(int x);
    void zag(int x);
    void Splay(int x);
    void Access(int x);
    void Make_rt(int x);
    void Link(int u,int v);
    void Cut(int u,int v);
    int Find(int x);
     
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("forest.in","r",stdin);
        freopen("forest.out","w",stdout);
    #endif
     
        n=in(),m=in();
        for(int i=1;i<=m;i++){
            e[i].u=in(),e[i].v=in(),e[i].a=in(),e[i].b=in();
            if(e[i].u==e[i].v) i--,m--;
        }
         
        int fx,fy,u,v,ans=0x3f3f3f3f;
         
        sort(e+1,e+m+1,cmp);
        for(int i=1;i<=n+m;i++) p[i]=i;
        for(int i=1;i<=n+m;i++) s[i].lc=i;
        for(int i=1;i<=m;i++){
            u=e[i].u,v=e[i].v;
            fx=Find(u),fy=Find(v);
            if(fx!=fy){
                s[i+n].dt=e[i].b;
                Link(u,i+n),Link(v,i+n);
                p[fx]=fy;
            }
            else{
                Make_rt(u),Access(v),Splay(v);
                if(s[v].mx>e[i].b){
                    int t=s[v].lc-n;
                    Cut(t+n,e[t].u),Cut(t+n,e[t].v);
                    s[i+n].dt=e[i].b;
                    Link(u,i+n),Link(v,i+n);
                }
            }
             
            if(Find(1)==Find(n)){
                Make_rt(1);Access(n);Splay(n);
                ans=min(ans,s[n].mx+e[i].a);
            }
        }
         
        if(ans==0x3f3f3f3f) ans=-1;
        printf("%d",ans);
        return 0;
    }
     
    void update(int x){
        s[x].mx=s[x].dt,s[x].lc=x;
        if(s[x].l && s[s[x].l].mx>s[x].mx) s[x].mx=s[s[x].l].mx,s[x].lc=s[s[x].l].lc;
        if(s[x].r && s[s[x].r].mx>s[x].mx) s[x].mx=s[s[x].r].mx,s[x].lc=s[s[x].r].lc;
    }
     
    void push_down(int x){
        if(s[x].rv){
            s[x].trans();
            if(s[x].l) s[s[x].l].rv^=1;
            if(s[x].r) s[s[x].r].rv^=1;
            s[x].rv=0;
        }
    }
     
    void Down_tag(int x){
        if(!s[x].rt) Down_tag(s[x].f);
        push_down(x);
    }
     
    void zig(int x){
        int y=s[x].f;s[x].f=s[y].f;
        if(s[y].rt) s[x].rt=true,s[y].rt=false;
        else{
            if(y==s[s[y].f].l) s[s[y].f].l=x;
            else s[s[y].f].r=x;
        }
        s[y].l=s[x].r;
        if(s[x].r) s[s[x].r].f=y;
        s[x].r=y,s[y].f=x;
        update(y);
    }
     
    void zag(int x){
        int y=s[x].f;s[x].f=s[y].f;
        if(s[y].rt) s[x].rt=true,s[y].rt=false;
        else{
            if(y==s[s[y].f].l) s[s[y].f].l=x;
            else s[s[y].f].r=x;
        }
        s[y].r=s[x].l;
        if(s[x].l) s[s[x].l].f=y;
        s[x].l=y,s[y].f=x;
        update(y);
    }
     
    void Splay(int x){
        Down_tag(x);
        while(!s[x].rt){
            int y=s[x].f;
            if(s[y].rt){ if(x==s[y].l) zig(x);
                else zag(x);}
            else{
                int z=s[y].f;
                if(y==s[z].l){ if(x==s[y].l) zig(y),zig(x);
                    else zag(x),zig(x);}
                else{ if(x==s[y].r) zag(y),zag(x);
                    else zig(x),zag(x);}
            }
        }
        update(x);
    }
     
    void Access(int x){
        for(int last=0;x;x=s[last=x].f){
            Splay(x);
            s[s[x].r].rt=true;
            s[s[x].r=last].rt=false;
            update(x);
        }
    }
     
    void Make_rt(int x){
        Access(x); Splay(x); s[x].rv=1;
    }
     
    void Link(int u,int v){
        Make_rt(u); s[u].f=v;
    }
     
    void Cut(int u,int v){
        Make_rt(u); Access(v); Splay(v);
        s[u].rt=true; s[u].f=s[v].f;
        s[v].l=s[v].f=0;
    }
     
    int Find(int x){
        int r=x,pre;
        while(r!=p[r]) r=p[r];
        while(r!=x)
            pre=p[x],p[x]=r,x=pre;
        return r;
    }
    View Code

    D2

    T1 动物园 ac通道

    给你一个串,让你求每个位置的满足不重复的相同前缀和后缀的个数。

    唔,比较容易想到的就是一种模拟的方法。

    每个位置都沿着next指针往后跳,看能在i/2之前跳多少次。

    但是这样的话是很容易卡你的,比如aaaaaaaaaaa,让你每次next都只跳一步= =这样的话就变成n^2了。

    然后比较好像到的就是我直接记忆化一下累加的结果。使用记忆化的话,你可以只要跳到第一个满足条件的位置就可以了。

    但是你跳到i/2前面的过程如果仍然使用模拟的话就会超时,理由同上。那么怎么求呢?

    笔者太傻了...没有想到直接沿着上一个的位置来就好了...和你求kmp的过程是完全一样的,只是这个的前引指针不是指向最长位置了,而是<i/2的最长位置。

    然后你后面的指针往后移动的时候,前面的指针还是可以和以前的一样跳。这样的话就是O(n)的了。

    感觉对kmp的思路比较清晰的话对这题是很有帮助的。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
     
    using namespace std;
     
    typedef long long ll;
    const int maxn=1000010;
    const int mod=1e9+7;
     
    int n,len;
    int next[maxn],cnt[maxn];
    char ch[maxn];
     
    void get_next(){
        int first=-1,last=0;
        next[0]=-1;
        while(last<len){
            if(first==-1 || ch[last]==ch[first]){
                first++,last++;
                next[last]=first;
                cnt[last]=cnt[first]+1;
            }
            else
                first=next[first];
        }
    }
     
    int get_cnt(){
        int ans=1,first=-1,last=0;
        while(last<len){
            if(first==-1 || ch[last]==ch[first]){
                first++,last++;
                while((first<<1)>last) first=next[first];
                ans=(ll)ans*(cnt[first]+1)%mod;
            }
            else
                first=next[first];
        }
        return ans;
    }
     
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("zoo.in","r",stdin);
        freopen("zoo.out","w",stdout);
    #endif
     
        int tmp;
        ll ans;
     
        scanf("%d",&n);
        while(n--){
            scanf("%s",ch);
            len=strlen(ch);
            get_next();
            printf("%d
    ",get_cnt());
        }
     
        return 0;
    }
    View Code

    T2 随机数生成器 ac通道

    告诉你一种生成随机数的方法,告诉你一种通过随机数生成排列的方法。然后把这个排列扔在一个n*m的地图上,让你选择一条从(1,1)到(n,m)的路径,使得这条路径上的数字从小到大排序之后得到的字典序最小。

    首先的那个部分可以模拟= =。但是你需要控制好空间,比如说随机数你就没有必要求出来,直接用来搞排列之类的...然后你那个地图也不要做出来,直接搞一个一维的挺好。

    然后就到了怎么找到这样一条路径了...感觉贪心的思路很自然。笔者趁机来秀一下gif[第一次做题解动图...可能没怎么画的好QAQ]。

    做了一个样例的求法...是不是很良心啊....

    好吧:样例不良心,但是笔者良心2333333

    大致的思路就是如此了,按从小到大的顺序,选择了之后将(1,1)到(x-1,y)的矩阵保留,把(x+1,y)到(n,n)的矩阵保留,剩余的删除。

    然后直到只剩下一条通路为止。

    首先我们要能找到每个点所在的位置,由于之前已经用了100MB了,那么我们最多再开一个...那就记录一个lc[T[i]]=i;然后把i%m和/m处理好了。

    但是怎么把矩阵保留|删除呢?...是不是要用二维树状数组呢?但是二维树状数组也会超时啊...因为你要进行判定的话,那么就比较恶心...每个点都要判断一下...就超时了

    那么我们直接暴力修改就好了。

    每行记录一个可以放的范围l[i]和r[i],然后每找到一个可以用的点就去暴力修改其它行的有关数据。

    由于需要修改的点只有n+m-1个,那么每次修改的复杂度即使是O(n)的也只有n^2;而判定是否合格每个位置都是O(1)的。

    最后复杂度还是N^2的但是常数很大而已啦...

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
     
    using namespace std;
     
    inline int in(){
        int x=0;char ch=getchar();
        while(ch>'9' || ch<'0') ch=getchar();
        while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
        return x;
    }
     
    const int maxn=5010;
    typedef long long ll;
     
    int n,m,nm,q;
    int x0,a,b,c,d;
    int T[maxn*maxn],rk[maxn*maxn];
    int l[maxn],r[maxn];
     
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("random.in","r",stdin);
        freopen("ramdom.out","w",stdout);
    #endif
     
        int x,u,v,tmp,x1,y1,cnt=0;
        bool flag=0;
     
        x0=in(),a=in(),b=in(),c=in(),d=in();
        n=in(),m=in();
        nm=n*m;
        for(int i=1;i<=nm;i++) T[i]=i;
         
        x=x0;
        for(int i=1;i<=nm;i++){
            x=((ll)a*x%d*x%d+(ll)b*x%d+c)%d;
            tmp=T[i],T[i]=T[x%i+1],T[x%i+1]=tmp;
            //swap(T[i],T[x%i+1]);
        }
         
        q=in();
        for(int i=1;i<=q;i++){
            u=in(),v=in();
            tmp=T[u],T[u]=T[v],T[v]=tmp;
            //swap(T[u],T[v]);
        }
        for(int i=1;i<=nm;i++) rk[T[i]]=i;
        for(int i=1;i<=n;i++) l[i]=1,r[i]=m;
        for(int i=1;i<=nm;i++){
            x1=rk[i]/m+1,y1=rk[i]%m;
            if(!y1) x1--,y1=m;
             
            if(y1>r[x1] || y1<l[x1]) continue;
            else{
                if(flag) printf(" %d",i);
                else flag=1,printf("%d",i);
                 
                for(int j=1;j<x1;j++) if(r[j]>y1) r[j]=y1;
                for(int j=x1+1;j<=n;j++) if(l[j]<y1) l[j]=y1;
                cnt++;
                if(cnt==n+m-1) break;
            }
        }
         
        return 0;
    }
    View Code
  • 相关阅读:
    JS自定义事件之选项卡
    架构MVC——JS中的理论
    jquery嵌套后会触发2次点击事件, jquery的unbind就是卸载这个点击事件的.
    【js与jquery】javascript中url编码与解码
    使用jquery获取url以及jquery获取url参数的方法
    js 正则匹配 小结
    Web前端开发规范文档
    HTTP及XMLHTTP状态代码一览
    css命名规则
    JS四级复选框选中层次关系
  • 原文地址:https://www.cnblogs.com/Robert-Yuan/p/5595892.html
Copyright © 2011-2022 走看看