zoukankan      html  css  js  c++  java
  • 清北学堂2018年1月省选强化班模拟考试1

    期望得分:100+100+40=240

    实际得分:100+100+20=220

    T1

    sum[r]^sum[l-1]<k

    对前缀异或和建trie树

    假设当前是第i位,sum[r]的地i位是l

    如果k的第i位为1,累加l,当前指针转到sum[r]的l^1

    否则,当前指针直接转到sum[r]的l

    #include<cstdio>
    #include<iostream>
    
    using namespace std;
    
    typedef long long LL;
    
    #define N 100001
    
    int bit[31];
    
    int tr[N*30][2],sum[N*30];
    
    int k;
    
    int tot=1,root=1;
    
    LL ans;
    
    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 insert(int x)
    {
        int now=root;
        bool j;
        for(int i=30;i>=0;--i)
        {
            j=x&bit[i];
            if(!tr[now][j]) tr[now][j]=++tot;
            now=tr[now][j];
            sum[now]++;
        }
    }
    
    void query(int x)
    {
        int now=root;
        bool l,r;
        for(int i=30;i>=0;--i)
        {
            if(!now) return;
            l=x&bit[i];
            r=l^1;
            if(k&bit[i])
            {
                ans+=sum[tr[now][l]];
                now=tr[now][r];
            }
            else now=tr[now][l];
        }
    }
    
    int main()
    {
        freopen("bit.in","r",stdin);
        freopen("bit.out","w",stdout);
        bit[0]=1;
        for(int i=1;i<=30;++i) bit[i]=bit[i-1]<<1;
        int n,x;
        read(n); read(k);
        insert(0);
        int pre=0;
        for(int i=1;i<=n;++i)
        {
            read(x);
            pre^=x;
            query(pre);
            insert(pre);
        }
        cout<<ans;
    }
    View Code

    T2

    线段树

    设sum[i]表示区间的和,sum2[i]表示区间数的平方和

    预处理pre1[i]:i^2的前缀和,pre2[i]:i*2的前缀和

    现在要对区间加首项为a1,公差为d的等差数列

    假设区间有4个数,A、B、C、D,区间大小siz=4

    原来的sum[i]=A+B+C+D

    现在的sum[i]=A+a1+B+a1+d+C+a1+2d+D+a1+3d

    即新的sum[i]=原来的sum[i]+siz*a1+(siz-1)*siz*d

    原来的sum2[i]=A^2+B^2+C^2+D^2

    现在的sum2[i]=(A+a1)^2 + (B+a1+d)^2 + (C+a1+2d)^2 + (D+a1+3d)^2 

    =A^2+a1^2+2*A*a1 + B^2+a1^2+d^2+2*B*a1+2*B*d+2*a1*d + C^2+a1^2+4*d^2+2*C*a1+4*C*d+4*a1*d + D^2+a1^2+9*d^2+2*D*a1+6*D*d+6*a1*d

    =(A^2+B^2+C^2+D^2)+(a1^2+a1^2+a1^2+a1^2)+(d^2+4*d^2+9*d^2)+(2*A*a1+2*B*a1+2*C*a1+2*D*a1)+(2*a1*d+4*a1*d+6*a1*d)+(2*B*d+4*C*d+6*D*d)

    =原来的sum2[i]+siz*a1^2+pre[siz-1]*d^2+2*原来的sum[i]*a1+pre[siz-1]*a1*d+pre[siz-1]*a1*d+ (2*B*d+4*C*d+6*D*d)

    最后的那个怎么维护?

    令sum3[i]表示0*A+1*B+2*C+3*D……

    最后那个就是sum[3]*2*d

    合并时,sum,sum2直接合并

    sum3[k]=sum3[L]+sum3[R]+siz[L]*sum[R]

    L:0*A+1*B+2*C

    R:0*D+1*E+2*F

    合并后:0*A+1*B+2*C+3*D+4*E+5*F

    合并后R的部分与子区间的R每个值差了siz[L]倍

    #include<cstdio>
    #include<iostream>
    
    using namespace std;
    
    const int mod=1000000007;
    
    #define N 100001
    
    typedef long long LL;
    
    LL pre1[N],pre2[N];
    
    LL siz[N<<2];
    LL sum[N<<2],sum2[N<<2],sum3[N<<2];
    LL fa1[N<<2],fd[N<<2];
    
    LL ans;
    
    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 read(LL &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    
    void pre(int n)
    {
        for(int i=1;i<=n;++i)
        {
            pre1[i]=(pre1[i-1]+i*i)%mod;
            pre2[i]=pre2[i-1]+i*2;
            pre2[i]-=pre2[i]>=mod ? mod : 0;
        }
    }
    
    void build(int k,int l,int r)
    {
        siz[k]=r-l+1;
        if(l==r)
        {
            read(sum[k]);
            sum2[k]=(sum[k]*sum[k])%mod;
            return;
        }
        int mid=l+r>>1;
        build(k<<1,l,mid);
        build(k<<1|1,mid+1,r);
        sum[k]=sum[k<<1]+sum[k<<1|1];
        sum[k]-=sum[k]>=mod ? mod : 0;
        sum2[k]=sum2[k<<1]+sum2[k<<1|1];
        sum2[k]-=sum2[k]>=mod ? mod : 0;
        sum3[k]=(sum3[k<<1]+siz[k<<1]*sum[k<<1|1]%mod+sum3[k<<1|1])%mod;
    }
    
    void insert_(int k,LL a1,LL d)
    {
        sum2[k]=(sum2[k]+a1*a1%mod*siz[k]%mod+d*d%mod*pre1[siz[k]-1]%mod+a1*d%mod*pre2[siz[k]-1]%mod+sum[k]*2*a1%mod+sum3[k]*d*2%mod)%mod;
        sum3[k]=(sum3[k]+siz[k]*(siz[k]-1)/2%mod*a1%mod+pre1[siz[k]-1]*d%mod)%mod;
        sum[k]=(sum[k]+siz[k]*a1%mod+siz[k]*(siz[k]-1)/2%mod*d%mod)%mod;
        fa1[k]+=a1; 
        fa1[k]-=fa1[k]>=mod ? mod : 0;
        fd[k]+=d;
        fd[k]-=fd[k]>=mod ? mod : 0;
    }
    
    void down(int k,int s)
    {
        insert_(k<<1,fa1[k],fd[k]);
        insert_(k<<1|1,(fa1[k]+s*fd[k])%mod,fd[k]);
        fa1[k]=fd[k]=0;
    }
    
    void insert(int k,int l,int r,int opl,int opr,LL a1,LL d)
    {
        if(l>=opl && r<=opr)
        {
            insert_(k,a1,d);
            return;
        }
        int mid=l+r>>1;
        if(fa1[k] || fd[k])  down(k,mid+1-l);
        if(opr<=mid) insert(k<<1,l,mid,opl,opr,a1,d);
        else if(opl>mid) insert(k<<1|1,mid+1,r,opl,opr,a1,d);
        else
        {
            insert(k<<1,l,mid,opl,mid,a1,d);
            insert(k<<1|1,mid+1,r,mid+1,opr,(a1+(mid+1-opl)*d)%mod,d);
        } 
        sum[k]=sum[k<<1]+sum[k<<1|1];
        sum[k]-=sum[k]>=mod ? mod : 0;
        sum2[k]=sum2[k<<1]+sum2[k<<1|1];
        sum2[k]-=sum2[k]>=mod ? mod : 0;
        sum3[k]=(sum3[k<<1]+siz[k<<1]*sum[k<<1|1]%mod+sum3[k<<1|1])%mod;
    }
    
    void query(int k,int l,int r,int opl,int opr,bool w)
    {
        if(l>=opl && r<=opr)
        {
            if(w) ans+=sum2[k];
            else ans+=sum[k];
            ans-=ans>=mod ? mod : 0;
            return;
        }
        int mid=l+r>>1;
        if(fa1[k] || fd[k])  down(k,mid+1-l);
        if(opl<=mid) query(k<<1,l,mid,opl,opr,w);
        if(opr>mid) query(k<<1|1,mid+1,r,opl,opr,w);
    }
    
    int main()
    {
        freopen("calculation.in","r",stdin);
        freopen("calculation.out","w",stdout);
        int n,m;
        read(n); read(m);
        pre(n);
        build(1,1,n);
        char c[3]; 
        int l,r,b,k;
        while(m--)
        {
            scanf("%s",c);
            if(c[0]=='A')
            {
                read(l); read(r); read(k); read(b);
                insert(1,1,n,l,r,b,k);
            }
            else 
            {
                read(l); read(r);
                ans=0;
                query(1,1,n,l,r,c[0]=='C');
                cout<<ans<<'
    ';
            }
        }
    }
    View Code

    T3

    求仙人掌的直径,DP

    可以去参考http://www.cnblogs.com/TheRoadToTheGold/p/7895298.html

     以前做过的类似的考场上写不出来没啥好说的

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    
    #define N 100001
    
    int front[N],to[N<<1],nxt[N<<1],val[N<<1];
    
    int tot,ans;
    
    int low[N],dfn[N];
    
    int fa[N],dep[N];
    
    int dp[N];
    
    int q[N],tmp[N<<1];
    int sum[N<<1];
    
    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 clear()
    {
        tot=1;
        ans=0;
        memset(front,0,sizeof(front));
        memset(dp,0,sizeof(dp));
        memset(dfn,0,sizeof(dfn));
    }
    
    void add(int u,int v,int w)
    {
        to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; val[tot]=w;
        to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; val[tot]=w;
    }
    
    void circle(int x,int y)
    {
        int cnt=dep[y]-dep[x]+1;
        int now=y;
        while(dfn[fa[now]]>=dfn[x]) tmp[cnt--]=now,now=fa[now];
        tmp[cnt]=now;
        cnt=dep[y]-dep[x]+1;
        int m=cnt;
        for(int i=1;i<=cnt;++i) tmp[++m]=tmp[i];
        for(int i=1;i<=cnt;++i)
            for(int j=front[tmp[i]];j;j=nxt[j])
                if(to[j]==tmp[i+1]) { sum[i+1]=val[j]; break; }
        for(int i=2;i<=cnt;++i) sum[i+cnt]=sum[i];
        for(int i=1;i<=m;++i) sum[i]+=sum[i-1];
        int h=0,t=0;
        for(int i=1;i<=m;++i)
        {
            while(h<t && i-q[h]>=cnt) h++;
            if(h<t) ans=max(ans,dp[tmp[i]]+dp[tmp[q[h]]]+sum[i]-sum[q[h]]);
            while(h<t && dp[tmp[i]]-sum[i]>dp[tmp[q[t-1]]]-sum[q[t-1]]) t--;
            q[t++]=i;
        }
        for(int i=2;i<=cnt;++i) dp[x]=max(dp[x],dp[tmp[i]]+max(sum[i],sum[cnt+1]-sum[i]));
    }
    
    void tarjan(int x,int y)
    {
        dfn[x]=low[x]=++tot;
        for(int i=front[x];i;i=nxt[i])
        {
            if(y==(i^1)) continue;
            if(!dfn[to[i]])
            {
                fa[to[i]]=x;
                dep[to[i]]=dep[x]+1;
                tarjan(to[i],i);
                low[x]=min(low[x],low[to[i]]);
            }
            else low[x]=min(low[x],dfn[to[i]]);
            if(low[to[i]]>dfn[x])
            {
                ans=max(ans,dp[x]+dp[to[i]]+val[i]);
                dp[x]=max(dp[x],dp[to[i]]+val[i]);
            }
        }
        for(int i=front[x];i;i=nxt[i])
            if(fa[to[i]]!=x && dfn[x]<dfn[to[i]]) circle(x,to[i]);
    }
    
    int main()
    {
        freopen("path.in","r",stdin);
        freopen("path.out","w",stdout);
        int T;
        int n,m;
        int u,v,w;
        read(T);
        while(T--)
        {
            clear();
            read(n); read(m);
            while(m--)
            {
                read(u); read(v); read(w);
                add(u,v,w);
            }
            tot=0;
            tarjan(1,0);
            cout<<ans<<'
    ';
        }
    }
    View Code

    Summary

    1、5个小时的时间,可以放心大胆的去写思路清晰的正解

    2、A掉题远比暴力带来的收益多,无论是分数还是心理

    3、一定要写对拍,今天如果没写对拍估计分数两位数

    4、一定要读好题,尤其是输入描述中先输入啥后输入啥,像这种:“A l r k b:在区间[l,r]上加上一个首项为b、公差为k的等差数列。”,今天就读成了A l r b k,白白浪费了半个小时

    5、当出现小数据正确,大数据错误时,去检查数组大小,今天T2的线段树一个数组没开4倍,又浪费了半小时

    6、要给不打算写正解的题留出充足的暴力时间,如今天的T3,至少50分的暴力因为时间原因写了40,得了20

    7、最后一道题,有正解思路但细节问题还没想好,不成熟,还剩不到一小时,果断选择写暴力,就像T3,如果不自量力选择去写正解,20分都没有了

    8、正常发挥,会的分都拿到,名次一定差不了。今天期望240(rank2),实际220(rank2),很多实力比我强的各种写炸。

    9、所以,将自己的实力在规定的时间、地点全部发挥出来,不留遗憾才是我现在要做的!

  • 相关阅读:
    hdu2191(多重背包)
    hdu3664(递推dp)
    hdu2955(变形01背包)
    hdu1712(分组背包)
    hdu1114(完全背包)
    hdu4004(二分)
    hdu2870(dp求最大子矩阵)
    POJ 1979 Red and Black(水题,递归)
    POJ 1922 Ride to School(贪心+模拟)
    POJ 1182 食物链(种类并查集)
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8284468.html
Copyright © 2011-2022 走看看