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

    NOIP2011

    Mayan游戏

    模拟题

    比较有意思的搜索,需要剪枝

    无脑枝:1.只有两个方块时直接return(不可能再消掉了) 2.不换颜色相同的

    有脑枝:发现左移和右移其实是一样的,当前块与右面块交换等于右面块与当前块交换

    然而左面为空时左移右移不同,特判一下

    (其实就是向左移只当左面为空时才移,其他任意一种情况都与右移等价)

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    ll mp[8][6],vis[10][10],sta[10],del[10][10];
    ll top,tt;
    const ll n=7,m=5;
    struct node{
        ll x,y;
        node(){}
        node(const ll &a,const ll &b){x=a,y=b;}
    };
    struct an{
        ll x,y,g;
        an(){}
        an(const ll &a,const ll &b,const ll &c){x=a,y=b,g=c;}
    }ans[7];
    deque<node> q,p;
    ll ok(ll x,ll y,ll opt){
        if(x>=1&&x<=n&&y>=1&&y<=m&&mp[x][y]==opt&&!vis[x][y]) return 1; 
        return 0;
    }
    void print(){
        puts("wwb");
        for(ll i=1;i<=n;i++,puts(""))
            for(ll j=1;j<=m;j++){
                printf("%lld ",mp[i][j]);
            }
    }
    void down(){
        for(ll i=1;i<=m;i++){
            top=0;
            for(ll j=1;j<=n;j++)
                if(mp[j][i])
                    sta[++top]=mp[j][i];
            for(ll j=1;j<=n;j++)
                mp[j][i]=0;
            for(ll j=1;j<=top;j++)
                mp[j][i]=sta[j];
        }
    }
    void xiao(){
        ll ok=0;
        down();    
        memset(del,0,sizeof(del));
        for(ll i=1;i<=n;i++)
            for(ll j=1;j<=m;j++){
                if(mp[i][j]){
                    if(i>1&&i<n){
                        if(mp[i][j]==mp[i+1][j]&&mp[i][j]==mp[i-1][j]){
                            del[i][j]=1,del[i+1][j]=1,del[i-1][j]=1;
                            ok=1;
                        }
                    }
                    if(j>1&&j<m){
                        if(mp[i][j]==mp[i][j-1]&&mp[i][j]==mp[i][j+1]){
                            del[i][j]=1,del[i][j-1]=1,del[i][j+1]=1;
                            ok=1;
                        }
                    }
                }
            }
        if(!ok) return ;
        for(ll i=1;i<=n;i++)
            for(ll j=1;j<=m;j++)
                if(del[i][j])
                    mp[i][j]=0;
        down();
        xiao();
        return ;
    }
    ll ttt;
    ll check(){
        for(ll i=1;i<=m;i++)
            if(mp[1][i]) return 0;
        return 1;
    }
    void cpy(ll x[][6],ll y[][6]){
        for(ll i=1;i<=n;i++)
            for(ll j=1;j<=m;j++)
                x[i][j]=y[i][j];
    }
    void dfs(ll cnt){
    //    printf("%lld
    ",cnt);
        if(check()&&cnt==tt+1){
            for(ll i=1;i<=tt;i++)
                printf("%lld %lld %lld
    ",ans[i].x,ans[i].y,ans[i].g);
            exit(0);
        }
        if(cnt>=tt+1) return ;
        ll mem[8][6];
        for(ll j=1;j<=m;j++)
            for(ll i=1;i<=n;i++){
                if(mp[i][j]){                
                    if(j!=m&&mp[i][j]!=mp[i][j+1]){
                        cpy(mem,mp);
                        ans[++ttt]=an(j-1,i-1,1);
                        swap(mp[i][j],mp[i][j+1]);
                        xiao();
                        dfs(cnt+1);ttt--;
                        cpy(mp,mem);
                    }
                    if(j!=1&&mp[i][j]!=mp[i][j-1]){
                        cpy(mem,mp);
                        ans[++ttt]=an(j-1,i-1,-1);
                        swap(mp[i][j],mp[i][j-1]);
                        xiao();
                        dfs(cnt+1);ttt--;
                        cpy(mp,mem);
                    }
    
                }
            }
    }
    ll cnt[7];
    int main(){
        scanf("%lld",&tt);ll x;
        x=1;while(x!=0){scanf("%lld",&x);mp[++cnt[1]][1]=x;}
        x=1;while(x!=0){scanf("%lld",&x);mp[++cnt[2]][2]=x;}
        x=1;while(x!=0){scanf("%lld",&x);mp[++cnt[3]][3]=x;}
        x=1;while(x!=0){scanf("%lld",&x);mp[++cnt[4]][4]=x;}
        x=1;while(x!=0){scanf("%lld",&x);mp[++cnt[5]][5]=x;}
        xiao();
        dfs(1);
        puts("-1");
    }
    View Code

    NOIP2014

    联合权值

    题解

    花5分钟写了写

    发现根本不用$Dp$,

    $O(n^2)$,max显然就是最大值*次大值,总和思考怎么算

    发现就是(sum[i]-w[y])*w[y],sum表示是所有与i相连点权值之和,

    $O(n)$式子

    显然可以优化,${sum[i]}^2-sumlimits_{y}{w[y]}^2$随便维护一下

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define mod 10007
    #define A 1111111
    ll tot,n,m,t,ans,mx;
    ll sum[A],nxt[A],ver[A],x[A],y[A],head[A],w[A],maxx[A],cimaxx[A],pingf[A];
    void add(ll x,ll y){
        nxt[++tot]=head[x],head[x]=tot,ver[tot]=y;
    }
    int main(){
        scanf("%lld",&n);m=n-1;
        for(ll i=1;i<=m;i++){
            scanf("%lld%lld",&x[i],&y[i]);
            add(x[i],y[i]);add(y[i],x[i]);
        }
        for(ll i=1;i<=n;i++){
            scanf("%lld",&w[i]);
        }
        for(ll i=1;i<=m;i++){
            (sum[x[i]]+=w[y[i]])%=mod,(sum[y[i]]+=w[x[i]])%=mod;
            (pingf[x[i]]+=w[y[i]]*w[y[i]])%=mod;
            (pingf[y[i]]+=w[x[i]]*w[x[i]])%=mod;
            if(w[y[i]]>maxx[x[i]]){
                cimaxx[x[i]]=maxx[x[i]];
                maxx[x[i]]=w[y[i]];
            }
            else if(w[y[i]]>cimaxx[x[i]]){
                cimaxx[x[i]]=w[y[i]];
            }
            if(w[x[i]]>maxx[y[i]]){
                cimaxx[y[i]]=maxx[y[i]];
                maxx[y[i]]=w[x[i]];
            }
            else if(w[x[i]]>cimaxx[y[i]]){
                cimaxx[y[i]]=w[x[i]];
            }
        }
        for(ll i=1;i<=n;i++){
            (ans+=sum[i]*sum[i]%mod-pingf[i])%mod;
            mx=max(cimaxx[i]*maxx[i],mx);
        }
        ans%=mod;
        printf("%lld ",mx);
        printf("%lld
    ",(ans+mod)%mod);
    }
    View Code

    NOIP2016

    蚯蚓

    题解

    暴力就是开一个堆维护,然后每次取出最大值,维护mark表示标准差可以85分

    正解是根据单调性不算标准差

    因为每次取出最大值,取出的最大值越来小,另外维护两个队列,维护切出的两部分蚯蚓

    剩下两部分蚯蚓也满足单调不升性质

    单调队列维护

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    deque<ll> w[4];
    ll n,m,q,u,v,t;
    ll mark,cnt,mxid,mx;
    ll ans[31111111],dl[31111111],o[31111111];
    double p;
    ll cmp(ll x,ll y){
        return x>y;
    }
    ll gettop(){
        mx=-123456789101112,mxid=0;
        if(!w[1].empty()){
            if(w[1].front()>mx){
                mx=w[1].front();
                mxid=1;
            }
        }
        if(!w[2].empty()){
            if(w[2].front()>mx){
                mx=w[2].front();
                mxid=2;
            }
        }
        if(!w[3].empty()){
            if(w[3].front()>mx){
                mx=w[3].front();
                mxid=3;
            }
        }
        w[mxid].pop_front();
        return mx;
    }
    ll wempty(){
        if(w[1].empty()&&w[2].empty()&&w[3].empty()) return 1;
        return 0;
    }
    int main(){
        scanf("%lld%lld%lld%lld%lld%lld",&n,&m,&q,&u,&v,&t);
        for(ll i=1;i<=n;i++){
            scanf("%lld",&o[i]);
        }
        sort(o+1,o+n+1,cmp);
        for(ll i=1;i<=n;i++){
            w[1].push_back(o[i]);
        }
        
        p=(double)(u)/(double)(v);
        for(ll i=1;i<=m;i++){
            ll x=gettop()+mark;
            double xx=p*x;
            ll x1=floor(p*x),x2=x-x1;
            mark+=q;
            
            w[2].push_back(x1-mark),w[3].push_back(x2-mark);
            ans[i]=x;
        }
        while(!wempty()){
            dl[++dl[0]]=gettop()+mark;
        }
        for(ll i=t;i<=m;i+=t)
            printf("%lld ",ans[i]);
        printf("
    ");
        for(ll i=t;i<=dl[0];i+=t)
            printf("%lld ",dl[i]);
        printf("
    ");
    }
    View Code

    NOIP2017

    列队

    题解

    易发现m列有些特殊

    前m-1列和m列拆开考虑

    开n棵线段树维护n行,在开一棵线段树维护最后一列

    每一次操作可简化为

    依次进行 1.当前行删除y 2.当前行前移 3.最后列删除x 4.最后列前移

    线段树维护查询第k大操作

    代码实现有很多技巧,很考验代码能力

    代码

    //依次进行
    //1.当前行删除y
    //2.当前行前移
    //3.最后列删除x
    //4.最后列前移
    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define A 11111111
    vector<ll> vec[A];
    ll ls[A],rs[A],v[A],toot[A];
    ll n,m,tot,cnt,q;
    void change(ll &x,ll l,ll r,ll val){
        if(!x) x=++cnt;
        v[x]++;
        if(l==r) return ;
        ll mid=(l+r)>>1;
        if(mid>=val) change(ls[x],l,mid,val);
        else change(rs[x],mid+1,r,val);
    }
    ll ask(ll &x,ll l,ll r,ll k){
        if(l==r) return l;
        ll mid=(l+r)>>1;
        ll sum=mid-l+1-v[ls[x]];
        if(sum>=k) return ask(ls[x],l,mid,k);
        else return ask(rs[x],mid+1,r,k-sum);
    }
    ll callast(ll x){
        //查询最后一列
        ll r=ask(toot[n+1],1,tot,x);
        change(toot[n+1],1,tot,r);
        return r<=n?(r-1)*m+m:vec[n+1][r-n-1];
    }
    ll calcommon(ll x,ll y){
        ll r=ask(toot[x],1,tot,y);
        change(toot[x],1,tot,r);
        return r<m?(x-1)*m+r:vec[x][r-m];
    }
    
    int main(){
        ll ret,tmp;
        scanf("%lld%lld%lld",&n,&m,&q);
        tot=max(n,m)+q;
        while(q--){
            ll x,y;
            scanf("%lld%lld",&x,&y);
            if(y==m){
                ret=callast(x);
                vec[n+1].push_back(ret);
                printf("%lld
    ",ret);
            }
            else{
                ret=calcommon(x,y);
                printf("%lld
    ",ret);
                vec[n+1].push_back(ret);
                tmp=callast(x);
                vec[x].push_back(tmp);
            }
        }
    }
    View Code

    NOIP2018

    货币系统

    题解

    性质,1.最简系统一定是给定系统子集

    2.最简系统任意一种货币不能被其他货币表示

    2是显然的

    1证明:假设非子集元素为x

    若x可以被最简系统表示加入它没用,若不能被表示出,你原本不能表示x,现在加上x可以表示x与最简系统矛盾了

    所以可以无脑背包

     

  • 相关阅读:
    关系型数据库和非关系型数据库的区别
    总结篇3-python数据结构和算法
    总结篇2-python进阶
    总结篇1-python基础
    测试sql星级判定函数
    1、Anyproxy简介
    Python内置logging模块-- 日志
    python+ selenium 绕过浏览器检测
    python-selenium,解决 遇到阿里无痕登录验证
    seldom
  • 原文地址:https://www.cnblogs.com/znsbc-13/p/11838397.html
Copyright © 2011-2022 走看看