• 2017 清北济南考前刷题Day 5 afternoon


    期望得分:100+100+30=230

    实际得分:0+0+0=30

    T1

    直接模拟

    #include<cstdio>
    #include<iostream>
    
    using namespace std;
    
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    
    #define N 1002
    
    int e[N][N],t[N],pos[N];
    
    int ans[N];
    
    int main()
    {
        //freopen("rotate.in","r",stdin);
        //freopen("rotate.out","w",stdout);
        int n,p,k,x;
        read(n); read(p); read(k);
        for(int i=1;i<=p;i++) 
        {
            read(e[i][0]); x=e[i][0];
            for(int j=1;j<=x;j++) read(e[i][j]);
        }
        for(int i=1;i<=n;i++) ans[i]=i,pos[i]=i;
        for(int i=p;i;i--)
        {
            x=e[i][0];
            for(int j=1;j<=n;j++) t[j]=pos[j];
            for(int j=1;j<x;j++) ans[pos[e[i][j]]]=e[i][j+1],t[e[i][j+1]]=pos[e[i][j]];
            ans[pos[e[i][x]]]=e[i][1]; t[e[i][1]]=pos[e[i][x]];
            for(int j=1;j<=n;j++) pos[j]=t[j];
            for(int j=1;j<=n;j++) cout<<ans[j]<<' ';
            cout<<'
    ';
        }
        for(int i=1;i<=n;i++) cout<<ans[i]<<' ';
    }
    View Code

    T2

    当固定区间左端点时,随着右端点的右移,ans 值 减小,or 值增加

    所以枚举左端点,二分右端点

    st 表查询区间ans、 or 值

    #include<cstdio>
    #include<cmath>
    #include<iostream>
    
    using namespace std;
    
    #define N 100001
    
    const int mod=1e9+7;
    
    int n,a,b,c,d;
    
    int And[N][17],Xor[N][17];
    
    int ans=0;
    
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    
    int query(int l,int r,bool ty)
    {
        int k=log((double)r-l+1)/log(2.0);
        if(ty) return And[l][k]&And[r-(1<<k)+1][k];
        return Xor[l][k]|Xor[r-(1<<k)+1][k];
    }
    
    void pre()
    {
        for(int j=1,k=1;j<17;j++,k<<=1)
            for(int i=1;i+k-1<=n;i++)
                And[i][j]=And[i][j-1]&And[i+k][j-1],
                Xor[i][j]=Xor[i][j-1]|Xor[i+k][j-1];
    }
    
    void solve()
    {
        int l,r,mid,al,ar,xl,xr,res;
        for(int i=1;i<=n;i++)
        {
            l=i;r=n;
            al=ar=xl=xr=-1;
            while(l<=r)
            {
                mid=l+r>>1;
                res=query(i,mid,1);
                if(res<=b) al=mid,r=mid-1;
                else l=mid+1;
            }
            if(al==-1) continue;
            l=al;r=n;
            while(l<=r)
            {
                mid=l+r>>1;
                res=query(i,mid,1);
                if(res>=a) ar=mid,l=mid+1;
                else r=mid-1;
            }
            if(ar==-1) continue;
            l=al;r=ar;
            while(l<=r)
            {
                mid=l+r>>1;
                res=query(i,mid,0);
                if(res>=c) xl=mid,r=mid-1;
                else l=mid+1;
            }
            if(xl==-1) continue;
            l=xl;r=ar;
            while(l<=r)
            {
                mid=l+r>>1;
                res=query(i,mid,0);
                if(res<=d) xr=mid,l=mid+1;
                else r=mid-1;
            }
            if(xr==-1) continue;
            ans+=xr-xl+1;
            ans-=ans>=mod ? mod : 0;
            //printf("%d
    ",ans);
        }
        printf("%d",ans);
    }
    
    int main()
    {
        freopen("range.in","r",stdin);
        freopen("range.out","w",stdout);
        read(n); read(a); read(b); read(c); read(d);
        for(int i=1;i<=n;i++) read(And[i][0]),Xor[i][0]=And[i][0];
        pre();
        solve();
    }
    View Code

    考场代码错误1

    错误的二分左右端点方法(以and为例):

    即每次判断是否同时满足>=a <=b 

    这样不满足单调性

    while(l<=r)
    {
      。。。。。。
      if(res>=a && res<=b) al=mid,r=mid-1;
      else l=mid+1;
    }

    while(l<=r)
    {
      。。。。。。
      if(res>=a && res<=b) ar=mid,l=mid+1;
      else r=mid-1;
    }

    比如在二分右端点时,算出mid >b 

    此时应该右移mid 使结果变小

    但在上面代码中不满足 if 条件,mid 左移

    正确的二分方式:

    while(l<=r)
    {
      。。。。。。
      if(res<=b) al=mid,r=mid-1;
      else l=mid+1;
    }

    while(l<=r)
    {
      。。。。。。
      if(res>=a) ar=mid,l=mid+1;
      else r=mid-1;
    }

    即注意二分的单调性

    考场代码错误2

    st 表 倍增预处理 数组越界

    T3

    n^3 树形背包

    dp[i][j] 表示 以i为根的子树中,捡到k个果子的方案数

    枚举x的每个子节点 t

    捡:g[j+h]+= dp[x][j]*dp[t][h]

    不捡:g[j] += dp[x][j] *   2^(siz[t]-1)

    这个t 操作完后,把g赋值给dp[x],即子树t与x合并,清空g 

     

    在枚举时加了个 if(!dp[x][j]) continue

    所有测试点0.06s 以内跑过

    复杂度变了? (我是真不会分析时间复杂度QWQ)

    还是不要忽视任何一点儿小优化

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    
    #define N 1001
    
    using namespace std;
    
    const int mod=1e9+7;
    
    int n,k;
    
    int val[N];
    
    int front[N],to[N<<1],nxt[N<<1],tot;
    
    int dp[N][N],g[N],siz[N];
    
    int bit[N];
    
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    
    void add(int u,int v)
    {
        to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
        to[++tot]=u; nxt[tot]=front[v]; front[v]=tot;
    }
    
    void dfs(int x,int fa)
    {
        siz[x]=1;
        if(val[x]<=k) dp[x][val[x]]=1;
        for(int i=front[x];i;i=nxt[i])
            if(to[i]!=fa) dfs(to[i],x),siz[x]+=siz[to[i]];
        for(int i=front[x];i;i=nxt[i])
        {
            int t=to[i];
            if(t==fa) continue;
            memset(g,0,sizeof(g));
            for(int j=0;j<=k;++j)
            {
                if(!dp[x][j]) continue;
                for(int h=0;h<=k;++h)
                {
                    if(j+h>k) break;
                    if(!dp[t][h]) continue;
                    g[j+h]+=1LL*dp[x][j]*dp[t][h]%mod;
                    g[j+h]%=mod;
                }
                g[j]+=1LL*dp[x][j]*bit[siz[t]-1]%mod;
                g[j]%=mod;
            }
            for(int j=0;j<=k;++j) dp[x][j]=g[j],g[j]=0;
        }
    }
    
    int main()
    {
        freopen("fruit.in","r",stdin);
        freopen("fruit.out","w",stdout);
        read(n); read(k);
        bit[0]=1;
        for(int i=1;i<=n;++i) bit[i]=bit[i-1]*2%mod;
        for(int i=1;i<=n;++i) read(val[i]);
        int u,v;
        for(int i=1;i<n;++i) read(u),read(v),add(u,v);
        dfs(1,0);
        cout<<dp[1][k];
    } 
    View Code

    标准的n^2

    先把父节点的值赋给子节点,再加回来

    不是很明白

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    
    #define N 1001
    
    using namespace std;
    
    const int mod=1e9+7;
    
    int n,k;
    
    int val[N];
    
    int front[N],to[N<<1],nxt[N<<1],tot;
    
    int dp[N][N];
    
    int bit[N];
    
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    
    void add(int u,int v)
    {
        to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
        to[++tot]=u; nxt[tot]=front[v]; front[v]=tot;
    }
    
    int dfs(int x,int fa)
    {
        int siz=1;
        for(int i=front[x];i;i=nxt[i])
        {
            if(to[i]==fa) continue;
            int t=to[i];
            for(int j=0;j<=k-val[t];++j) dp[t][j+val[t]]=dp[x][j];
            int tmp=dfs(to[i],x);
            for(int j=0;j<=k;++j) dp[x][j]=(dp[t][j]+1LL*dp[x][j]*bit[tmp-1]%mod)%mod;
            siz+=tmp;
        }
        return siz;
    }
    
    int main()
    {
        freopen("fruit.in","r",stdin);
        freopen("fruit.out","w",stdout);
        read(n); read(k);
        bit[0]=1;
        for(int i=1;i<=n;++i) bit[i]=bit[i-1]*2%mod;
        for(int i=1;i<=n;++i) read(val[i]);
        int u,v;
        for(int i=1;i<n;++i) read(u),read(v),add(u,v);
        //for(int i=1;i<=n;i++) dp[i][val[i]]=1;
        dp[1][val[1]]=1;
        dfs(1,0);
        cout<<dp[1][k];
    } 
    View Code
  • 相关阅读:
    hibernate01
    利用Struts2拦截器完成文件上传功能
    layui的CRUD案例
    最大流dinic模板 poj1273
    CodeForces
    POJ 2139 Six Degrees of Cowvin Bacon (floyd)
    POJ 3259 Wormholes (floyd或者spfa)
    POJ 3615 Cow Hurdles (flyod)
    Codeforces Round #446 (Div. 1) A. Pride
    Educational Codeforces Round 34 A. Hungry Student Problem
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7768498.html
Copyright © 2020-2023  润新知