九下五月下旬日记

5.21

闲话

  • 早操忘换操前读了,还拿着理化实验的题签来读,幸好现班主任早操没来查。
  • 政治课做了三轮复习的宣讲。
  • 数学课上,称下节课开三轮复习。
  • 物理课上,现物理老师再次对我们回班后能否适应感到担忧。
  • \(miaomiao\)@yswn@APJifengc@IIIIIlIIIl 带回来了。@yswn 进来后还抓拍了一张机房照片。接着因后排机位“不足”爆发了一场“占机位大赛”。
  • 晚三现语文老师突然问我们这节课是否有安排,在我们回答没有后让我们帮她批改 \(23,24\) 班的语文卷子。

做题纪要

UVA12345 Dynamic len(set(a[L:R]))

  • 带修莫队板子。

    点击查看代码
    int a[1000010],cnt[1000010],L[1000010],R[1000010],pos[1000010],ans[1000010],klen,ksum;
    struct ask
    {
        int l,r,id,tim;
    }q[1000010];
    struct change
    {
        int pos,col;
    }c[1000010];
    bool q_cmp(ask a,ask b)
    {
        return (pos[a.l]==pos[b.l])?((pos[a.r]==pos[b.r])?(a.tim<b.tim):(a.r<b.r)):(a.l<b.l);
    }
    void init(int n)
    {
        klen=pow(n,2.0/3);
        ksum=n/klen;
        for(int i=1;i<=ksum;i++)
        {
            L[i]=R[i-1]+1;
            R[i]=R[i-1]+klen;
        }
        if(R[ksum]<n)
        {
            ksum++;
            L[ksum]=R[ksum-1]+1;
            R[ksum]=n;
        }
        for(int i=1;i<=ksum;i++)
        {
            for(int j=L[i];j<=R[i];j++)
            {
                pos[j]=i;
            }
        }
    }
    void add(int x,int &sum)
    {
        cnt[x]++;
        sum+=(cnt[x]==1);
    }
    void del(int x,int &sum)
    {
        cnt[x]--;
        sum-=(cnt[x]==0);
    }
    int main()
    {	
        int n,m,l=1,r=0,tim=0,sum=0,qcnt=0,ccnt=0,i;
        char pd;
        cin>>n>>m;
        for(i=1;i<=n;i++)
        {
            cin>>a[i];
        }
        init(n);
        for(i=1;i<=m;i++)
        {
            cin>>pd;
            if(pd=='Q')
            {
                qcnt++;
                cin>>q[qcnt].l>>q[qcnt].r;
                q[qcnt].l++;
                q[qcnt].id=qcnt;
                q[qcnt].tim=ccnt;
            }
            else
            {
                ccnt++;
                cin>>c[ccnt].pos>>c[ccnt].col;
                c[ccnt].pos++;
            }
        }
        sort(q+1,q+1+qcnt,q_cmp);	
        for(i=1;i<=qcnt;i++)
        {
            while(l>q[i].l)
            {
                l--;
                add(a[l],sum);
            }
            while(r<q[i].r)
            {
                r++;
                add(a[r],sum);
            }
            while(l<q[i].l)
            {
                del(a[l],sum);
                l++;
            }
            while(r>q[i].r)
            {
                del(a[r],sum);
                r--;
            }
            while(tim<q[i].tim)
            {
                tim++;
                if(l<=c[tim].pos&&c[tim].pos<=r)
                {
                    del(a[c[tim].pos],sum);
                    add(c[tim].col,sum);
                }
                swap(a[c[tim].pos],c[tim].col);
            }
            while(tim>q[i].tim)
            {
                if(l<=c[tim].pos&&c[tim].pos<=r)
                {
                    del(a[c[tim].pos],sum);
                    add(c[tim].col,sum);
                }
                swap(a[c[tim].pos],c[tim].col);
                tim--;
            }
            ans[q[i].id]=sum;
        }
        for(i=1;i<=qcnt;i++)
        {
            cout<<ans[i]<<endl;
        }
        return 0;
    }
    

UVA1674 Lightning Energy Report

  • 路径修改、单点查询板子。

    点击查看代码
    struct node
    {
        int nxt,to;
    }e[100010];
    int head[100010],c[100010],cc[100010],siz[100010],fa[100010],dep[100010],son[100010],top[100010],dfn[100010],cnt=0,tot=0;
    struct SMT
    {
        struct SegmentTree
        {
            int l,r,sum,lazy;
        }tree[200010];
        int lson(int x)
        {
            return x*2;
        }
        int rson(int x)
        {
            return x*2+1;
        }
        void pushup(int rt)
        {
            tree[rt].sum=tree[lson(rt)].sum+tree[rson(rt)].sum;
        }
        void build(int rt,int l,int r)
        {
            tree[rt].l=l;
            tree[rt].r=r;
            tree[rt].lazy=0;
            if(l==r)
            {
                tree[rt].sum=cc[l];
                return;
            }
            int mid=(l+r)/2;
            build(lson(rt),l,mid);
            build(rson(rt),mid+1,r);
            pushup(rt);
        }
        void pushdown(int rt)
        {
            if(tree[rt].lazy!=0)
            {
                tree[lson(rt)].sum+=tree[rt].lazy*(tree[lson(rt)].r-tree[lson(rt)].l+1);
                tree[rson(rt)].sum+=tree[rt].lazy*(tree[rson(rt)].r-tree[rson(rt)].l+1);
                tree[lson(rt)].lazy+=tree[rt].lazy;
                tree[rson(rt)].lazy+=tree[rt].lazy;
                tree[rt].lazy=0;
            }
        }
        void update(int rt,int x,int y,int val)
        {
            if(x<=tree[rt].l&&tree[rt].r<=y)
            {
                tree[rt].sum+=val*(tree[rt].r-tree[rt].l+1);
                tree[rt].lazy+=val;
                return;
            }
            pushdown(rt);
            int mid=(tree[rt].l+tree[rt].r)/2;
            if(x<=mid)
            {
                update(lson(rt),x,y,val);
            }
            if(y>mid)
            {
                update(rson(rt),x,y,val);
            }
        }
        int query(int rt,int x,int y)
        {
            if(x<=tree[rt].l&&tree[rt].r<=y)
            {
                return tree[rt].sum;
            }
            pushdown(rt);
            int mid=(tree[rt].l+tree[rt].r)/2,ans=0;
            if(x<=mid)
            {
                ans+=query(lson(rt),x,y);
            }
            if(y>mid)
            {
                ans+=query(rson(rt),x,y);
            }
            return ans;
        }
    }T;
    void add(int u,int v)
    {
        cnt++;
        e[cnt].nxt=head[u];
        e[cnt].to=v;
        head[u]=cnt;
    }
    void dfs1(int x,int father)
    {
        siz[x]=1;
        fa[x]=father;
        dep[x]=dep[father]+1;
        for(int i=head[x];i!=0;i=e[i].nxt)
        {
            if(e[i].to!=father)
            {
                dfs1(e[i].to,x);
                siz[x]+=siz[e[i].to];
                son[x]=(siz[e[i].to]>siz[son[x]])?e[i].to:son[x];
            }
        }
    }
    void dfs2(int x,int father,int id)
    {
        top[x]=id;
        tot++;
        dfn[x]=tot;
        cc[tot]=c[x];
        if(son[x]!=0)
        {
            dfs2(son[x],x,id);
            for(int i=head[x];i!=0;i=e[i].nxt)
            {
                if(e[i].to!=father&&e[i].to!=son[x])
                {
                    dfs2(e[i].to,x,e[i].to);
                }
            }
        }
    }
    void update1(int u,int v,int val)
    {
        while(top[u]!=top[v])
        {
            if(dep[top[u]]>dep[top[v]])
            {
                T.update(1,dfn[top[u]],dfn[u],val);
                u=fa[top[u]];
            }
            else
            {
                T.update(1,dfn[top[v]],dfn[v],val);
                v=fa[top[v]];
            }
        }
        if(dep[u]<dep[v])
        {
            T.update(1,dfn[u],dfn[v],val);
        }
        else
        {
            T.update(1,dfn[v],dfn[u],val);
        }
    }
    int query1(int pos)
    {
        return T.query(1,dfn[pos],dfn[pos]);
    }
    int main()
    {
        int t,n,m,u,v,w,i,j;
        cin>>t;
        for(j=1;j<=t;j++)
        {
            cnt=tot=0;
            memset(e,0,sizeof(e));
            memset(head,0,sizeof(head));
            memset(son,0,sizeof(son));
            cin>>n;
            for(i=1;i<=n-1;i++)
            {
                cin>>u>>v;
                u++;
                v++;
                add(u,v);
                add(v,u);
            }
            dfs1(1,0);
            dfs2(1,0,1);
            T.build(1,1,n);
            cin>>m;
            for(i=1;i<=m;i++)
            {
                cin>>u>>v>>w;
                u++;
                v++;
                update1(u,v,w);
            }
            cout<<"Case #"<<j<<":"<<endl;
            for(i=1;i<=n;i++)
            {
                cout<<query1(i)<<endl;
            }
        }
        return 0;
    }
    

UVA10905 Children's Game

  • 多倍经验: luogu P1012 [NOIP1998 提高组] 拼数

    点击查看代码
    string a[100];
    bool cmp(string a,string b)
    {
        return a+b>b+a;
    }
    int main()
    {
        int n,i;
        while(cin>>n)
        {
            if(n==0)
            {
                break;
            }
            else
            {
                for(i=1;i<=n;i++)
                {
                    cin>>a[i];
                }
                sort(a+1,a+1+n,cmp);
                for(i=1;i<=n;i++)
                {
                    cout<<a[i];
                }
                cout<<endl;
            }
        }
        return 0;
    }
    

luogu P4309 [TJOI2013] 最长上升子序列

  • 由于每次插入的数是递增的,原本的状态转移方程 \(f_{i}=\max\limits_{j=1}^{i-1} \{ [j<i] \times [a_{j}<a_{i}] \times f_{j} \}+1\) 可以简化成 \(f_{i}=\max\limits_{j=1}^{i-1} \{ [j<i] \times f_{j} \}+1\)

  • 平衡树在动态插入的过程中,维护 \(f\) 即可。

    点击查看代码
        struct BST
    {
        const int INF=0x7f7f7f7f;
        int rt_sum,root;
        struct FHQ_Treap
        {
            int son[2],val,rnd,cnt,siz,f;
        }tree[100010];
        #define lson(rt) (tree[rt].son[0])
        #define rson(rt) (tree[rt].son[1])
        BST()
        {
            rt_sum=root=0;
            srand(time(0));
        }
        void pushup(int rt)
        {
            tree[rt].siz=tree[lson(rt)].siz+tree[rson(rt)].siz+tree[rt].cnt;
            tree[rt].f=max(tree[rt].val,max(tree[lson(rt)].f,tree[rson(rt)].f));
        }
        int build(int val)
        {
            rt_sum++;
            lson(rt_sum)=rson(rt_sum)=0;
            tree[rt_sum].val=tree[rt_sum].f=val;
            tree[rt_sum].rnd=rand();
            tree[rt_sum].cnt=tree[rt_sum].siz=1;
            return rt_sum;
        }
        void split(int rt,int k,int &ls,int &rs)
        {
            if(rt==0)
            {
                ls=rs=0;
                return;
            }
            if(tree[lson(rt)].siz+tree[rt].cnt<=k)
            {
                ls=rt;
                split(rson(rt),k-tree[lson(rt)].siz-tree[rt].cnt,rson(ls),rs);
            }
            else
            {
                rs=rt;
                split(lson(rs),k,ls,lson(rs));
            }
            pushup(rt);
        }
        int merge(int rt1,int rt2)
        {
            if(rt1==0||rt2==0)
            {
                return rt1+rt2;
            }
            if(tree[rt1].rnd<tree[rt2].rnd)
            {
                rson(rt1)=merge(rson(rt1),rt2);
                pushup(rt1);
                return rt1;
            }
            else
            {
                lson(rt2)=merge(rt1,lson(rt2));
                pushup(rt2);
                return rt2;
            }
        }
        int query(int rt)
        {
            return tree[rt].f;
        }
        void insert(int pos)
        {
            int ls,rs;
            split(root,pos,ls,rs);
            root=merge(merge(ls,build(query(ls)+1)),rs);
        }
    }T;
    int main()
    {
        int n,x,i;
        cin>>n;
        for(i=1;i<=n;i++)
        {
            cin>>x;
            T.insert(x);
            cout<<T.query(T.root)<<endl;
        }
        return 0;
    }
    

5.22

闲话

  • 历史课上现历史老师讲了下信息技术和计算机技术的区别,先问的是班里有没有学信奥的(他是知道班里有的),然后问我们一亿的运算量大概是什么概念,我脱口而出其差不多就是现在普及的计算机 \(1s\) 的运算量(又忘了一亿是 \(1e8\) 了。。。),然后问我们超级计算机在实际生活的用途。
  • 不知道为啥把 \(4\) 楼机房门上的玻璃全拆了,还在 \(5\) 楼的门上划好了装玻璃的痕迹(教练是看平常机房太闷了吗?)。
  • 去厕所时途径 \(4\) 楼时,看见原班主任在给高一的讲变量初始化相关东西。
  • 晚上回宿舍后发现电话线被断了(上次年级部开家长会时说了,但我没当回事),什么傻逼学校,我是真搞不懂断电话线和备战中考有什么关系。

做题纪要

luogu P3165 [CQOI2014] 排序机械臂

  • 多倍经验: luogu P4402 [Cerc2007] robotic sort 机械排序 | SP2059 CERC07S - Robotic Sort | UVA1402 Robotic Sort

  • 由于每个数的下标不再等于权值,仍将下标插入到文艺平衡树中,同时记录插入的节点使其作为第二关键字参与排序(第一关键字为 \(P\) )。

  • 每次操作时,将第二维旋转至根节点,此时左子树的大小即为所求(因为有哨兵)。

  • 因为旋转顺序的不同,注意在 splay 的过程中也需要涉及到 pushdown

    点击查看代码
    pair<int,int>a[100010];
    struct BST
    {
        const int INF=0x7f7f7f7f;
        int rt_sum,root;
        struct Splay
        {
            int son[2],fa,val,cnt,siz,lazy;
        }tree[100010];
        #define lson(rt) (tree[rt].son[0])
        #define rson(rt) (tree[rt].son[1])
        #define dson(rt,d) (tree[rt].son[d])
        #define ason(rt,d) (tree[rt].son[d^1])
        BST()
        {
            rt_sum=root=0;
            insert(INF);
            insert(-INF);
        }
        int fdson(int rt)
        {
            return ((rt==lson(tree[rt].fa))?0:1);
        }
        void pushup(int rt)
        {
            tree[rt].siz=tree[lson(rt)].siz+tree[rson(rt)].siz+tree[rt].cnt;
        }
        int build(int val,int fa)
        {
            rt_sum++;
            lson(rt_sum)=rson(rt_sum)=0;
            tree[rt_sum].fa=fa;
            tree[rt_sum].val=val;
            tree[rt_sum].cnt=tree[rt_sum].siz=1;
            return rt_sum;
        }
        void pushdown(int rt)
        {
            if(rt!=0&&tree[rt].lazy!=0)
            {
                swap(lson(rt),rson(rt));
                tree[lson(rt)].lazy^=1;
                tree[rson(rt)].lazy^=1;
                tree[rt].lazy=0;
            }
        }
        void rotate(int x)
        {
            int y=tree[x].fa,z=tree[y].fa,d=fdson(x);
            dson(z,fdson(y))=x;
            tree[x].fa=z;
            dson(y,d)=ason(x,d);
            tree[ason(x,d)].fa=y;
            ason(x,d)=y;
            tree[y].fa=x;
            pushup(y);
            pushup(x);
        }
        void splay(int x,int to)
        {
            while(tree[x].fa!=to)
            {
                int y=tree[x].fa,z=tree[y].fa;
                pushdown(z);
                pushdown(y);
                pushdown(x);
                if(z!=to)
                {
                    rotate((fdson(x)==fdson(y))?y:x);
                }
                rotate(x);
            }
            root=(to==0)?x:root;
        }
        int insert(int val)
        {
            int rt=root,fa=0;
            while(rt!=0&&tree[rt].val!=val)
            {
                fa=rt;
                rt=dson(rt,val>tree[rt].val);
            }
            if(rt==0)
            {
                rt=build(val,fa);
                if(fa!=0)
                {
                    dson(fa,val>tree[fa].val)=rt;
                }
            }
            else
            {
                tree[rt].cnt++;
            }
            splay(rt,0);
            return rt;
        }
        int kth_min_idx_INF(int rt,int k)
        {
            pushdown(rt);
            if(rt==0)
            {
                return 0;
            }
            if(k<=tree[lson(rt)].siz)
            {
                return kth_min_idx_INF(lson(rt),k);
            }
            else
            {
                if(tree[lson(rt)].siz+tree[rt].cnt<k)
                {
                    return kth_min_idx_INF(rson(rt),k-tree[lson(rt)].siz-tree[rt].cnt);
                }
                else
                {
                    return rt;
                }
            }
        }
        int kth_min_idx(int rt,int k)
        {
            return kth_min_idx_INF(rt,k+1);
        }
        int split(int l,int r)
        {
            l=kth_min_idx(root,l-1);
            r=kth_min_idx(root,r+1);
            splay(l,0);
            splay(r,l);
            return lson(rson(l));
        }
        void reverse(int l,int r)
        {
            tree[split(l,r)].lazy^=1;
        }
        int query(int val)
        {
            splay(val,0);
            return tree[lson(root)].siz-1+1;
        }
    }T;
    int main()
    {
        int n,ans,i;
        cin>>n;
        for(i=1;i<=n;i++)
        {
            cin>>a[i].first;
            a[i].second=T.insert(i);
        }	
        sort(a+1,a+1+n);
        for(i=1;i<=n;i++)
        {
            ans=T.query(a[i].second);
            T.reverse(i,ans);
            cout<<ans<<" ";
        }
        return 0;
    }
    

luogu P4146 序列终结者

  • 额外维护一个增量标记即可,由于 pushup 时涉及到对左右儿子节点(不一定存在)取 \(\max\) ,注意特判即可。

    点击查看代码
    struct BST
    {
        const int INF=0x7f7f7f7f;
        int rt_sum,root;
        struct FHQ_Treap
        {
            int son[2],idx,val,rnd,cnt,siz,lazy_add,lazy_reverse,maxx;
        }tree[100010];
        #define lson(rt) (tree[rt].son[0])
        #define rson(rt) (tree[rt].son[1])
        BST()
        {
            rt_sum=root=0;
            srand(time(0));
        }
        void pushup(int rt)
        {
            tree[rt].siz=tree[lson(rt)].siz+tree[rson(rt)].siz+tree[rt].cnt;
            tree[rt].maxx=tree[rt].val;
            if(lson(rt)!=0)
            {
                tree[rt].maxx=max(tree[rt].maxx,tree[lson(rt)].maxx);
            }
            if(rson(rt)!=0)
            {
                tree[rt].maxx=max(tree[rt].maxx,tree[rson(rt)].maxx);
            }
        }
        int build(int val)
        {
            rt_sum++;
            lson(rt_sum)=rson(rt_sum)=tree[rt_sum].lazy_add=tree[rt_sum].lazy_reverse=0;
            tree[rt_sum].idx=val;
            tree[rt_sum].val=tree[rt_sum].maxx=0;
            tree[rt_sum].rnd=rand();
            tree[rt_sum].cnt=tree[rt_sum].siz=1;
            return rt_sum;
        }
        void pushdown(int rt)
        {
            if(rt!=0&&tree[rt].lazy_reverse!=0)
            {
                swap(lson(rt),rson(rt));
                tree[lson(rt)].lazy_reverse^=1;
                tree[rson(rt)].lazy_reverse^=1;
                tree[rt].lazy_reverse=0;
            }
            if(rt!=0&&tree[rt].lazy_add!=0)
            {
                tree[lson(rt)].val+=tree[rt].lazy_add;
                tree[rson(rt)].val+=tree[rt].lazy_add;
                tree[lson(rt)].maxx+=tree[rt].lazy_add;
                tree[rson(rt)].maxx+=tree[rt].lazy_add;
                tree[lson(rt)].lazy_add+=tree[rt].lazy_add;
                tree[rson(rt)].lazy_add+=tree[rt].lazy_add;
                tree[rt].lazy_add=0;
            }
        }
        void split(int rt,int k,int &ls,int &rs)
        {
            if(rt==0)
            {
                ls=rs=0;
                return;
            }
            pushdown(rt);
            if(tree[lson(rt)].siz+tree[rt].cnt<=k)
            {
                ls=rt;
                split(rson(ls),k-tree[lson(rt)].siz-tree[rt].cnt,rson(ls),rs);
            }
            else
            {
                rs=rt;
                split(lson(rs),k,ls,lson(rs));
            }
            pushup(rt);
        }
        int merge(int rt1,int rt2)
        {
            if(rt1==0||rt2==0)
            {
                return rt1+rt2;
            }
            if(tree[rt1].rnd<tree[rt2].rnd)
            {
                pushdown(rt1);
                rson(rt1)=merge(rson(rt1),rt2);
                pushup(rt1);
                return rt1;
            }
            else
            {
                pushdown(rt2);
                lson(rt2)=merge(rt1,lson(rt2));
                pushup(rt2);
                return rt2;
            }
        }
        void insert(int val)
        {
            int ls,rs;
            split(root,val,ls,rs);
            root=merge(merge(ls,build(val)),rs);
        }
        void update(int l,int r,int val)
        {
            int ls,rs,mid;
            split(root,r,ls,rs);
            split(ls,l-1,ls,mid);
            tree[mid].val+=val;
            tree[mid].maxx+=val;
            tree[mid].lazy_add+=val;
            root=merge(merge(ls,mid),rs);
        }
        void reverse(int l,int r)
        {
            int ls,rs,mid;
            split(root,r,ls,rs);
            split(ls,l-1,ls,mid);
            tree[mid].lazy_reverse^=1;
            root=merge(merge(ls,mid),rs);
        }
        int query(int l,int r)
        {
            int ls,rs,mid,ans;
            split(root,r,ls,rs);
            split(ls,l-1,ls,mid);
            ans=tree[mid].maxx;
            root=merge(merge(ls,mid),rs);
            return ans;
        }
    }T;
    int main()
    {
        int n,m,i,pd,l,r,val;
        cin>>n>>m;
        for(i=1;i<=n;i++)
        {
            T.insert(i);
        }
        for(i=1;i<=m;i++)
        {
            cin>>pd>>l>>r;
            if(pd==1)
            {
                cin>>val;
                T.update(l,r,val);
            }
            if(pd==2)
            {
                T.reverse(l,r);
            }
            if(pd==3)
            {
                cout<<T.query(l,r)<<endl;
            }
        }
        return 0;
    }
    

UVA11922 Permutation Transformer

  • 由于需要翻转后放到末尾,故 \(FHQ-Treap\) 在合并时跳着合并即可。

    点击查看代码
    struct BST
    {
        const int INF=0x7f7f7f7f;
        int rt_sum,root;
        struct FHQ_Treap
        {
            int son[2],val,rnd,cnt,siz,lazy;
        }tree[100010];
        #define lson(rt) (tree[rt].son[0])
        #define rson(rt) (tree[rt].son[1])
        BST()
        {
            rt_sum=root=0;
            srand(time(0));
        }
        void pushup(int rt)
        {
            tree[rt].siz=tree[lson(rt)].siz+tree[rson(rt)].siz+tree[rt].cnt;
        }
        int build(int val)
        {
            rt_sum++;
            lson(rt_sum)=rson(rt_sum)=tree[rt_sum].lazy=0;
            tree[rt_sum].val=val;
            tree[rt_sum].rnd=rand();
            tree[rt_sum].cnt=tree[rt_sum].siz=1;
            return rt_sum;
        }
        void pushdown(int rt)
        {
            if(rt!=0&&tree[rt].lazy!=0)
            {
                swap(lson(rt),rson(rt));
                tree[lson(rt)].lazy^=1;
                tree[rson(rt)].lazy^=1;
                tree[rt].lazy=0;
            }
        }
        void split(int rt,int k,int &ls,int &rs)
        {
            if(rt==0)
            {
                ls=rs=0;
                return;
            }
            pushdown(rt);
            if(tree[lson(rt)].siz+tree[rt].cnt<=k)
            {
                ls=rt;
                split(rson(ls),k-tree[lson(rt)].siz-tree[rt].cnt,rson(ls),rs);
            }
            else
            {
                rs=rt;
                split(lson(rs),k,ls,lson(rs));
            }
            pushup(rt);
        }
        int merge(int rt1,int rt2)
        {
            if(rt1==0||rt2==0)
            {
                return rt1+rt2;
            }
            if(tree[rt1].rnd<tree[rt2].rnd)
            {
                pushdown(rt1);
                rson(rt1)=merge(rson(rt1),rt2);
                pushup(rt1);
                return rt1;
            }
            else
            {
                pushdown(rt2);
                lson(rt2)=merge(rt1,lson(rt2));
                pushup(rt2);
                return rt2;
            }
        }
        void insert(int val)
        {
            int ls,rs;
            split(root,val,ls,rs);
            root=merge(merge(ls,build(val)),rs);
        }
        void reverse(int l,int r)
        {
            int ls,rs,mid;
            split(root,r,ls,rs);
            split(ls,l-1,ls,mid);
            tree[mid].lazy^=1;
            root=merge(merge(ls,rs),mid);
        }
        void inorder(int rt)
        {
            if(rt!=0)
            {
                pushdown(rt);
                inorder(lson(rt));
                cout<<tree[rt].val<<endl;
                inorder(rson(rt));
            }
        }
    }T;
    int main()
    {
        int n,m,l,r,i;
        cin>>n>>m;
        for(i=1;i<=n;i++)
        {
            T.insert(i);
        }
        for(i=1;i<=m;i++)
        {
            cin>>l>>r;
            T.reverse(l,r);
        }
        T.inorder(T.root);
        return 0;
    }
    

5.23

闲话

  • 早上到机房后,发现门上已经把昨天划的痕迹的区域给割下来了,然后就安上了木头边框,用胶水固定了玻璃。但 \(3\) 机房又用语文习字纸/作文升格纸盖上了,没什么意义。
  • 物理课现物理老师让我们改一改不写作业的习惯。
  • 详见 2024 HE中考 游记 5.23

做题纪要

BZOJ2839 集合计数

  • 考虑二项式反演。

  • \(f_{m}\) 表示交集中恰好有 \(m\) 个元素的方案数, \(g_{m}\) 表示交集中至少有 \(m\) 个元素的方案数,即 \(g_{m}=\sum\limits_{i=m}^{n}\dbinom{i}{m}f_{i}\) ,那么有 \(f_{m}=\sum\limits_{i=m}^{n}(-1)^{i-m}\dbinom{i}{m}g_{i}\)

  • 现在问题转化为怎么求 \(g_{m}\) 。先钦定选出的 \(m\) 个元素,此时方案数为 \(\dbinom{n}{m}\) ;接着剩下的 \(n-m\) 个元素一共可以组成 \(2^{n-m}\) 个集合(包括空集),又因为这些集合中至少要选 \(1\) 个,故状态转移方程为 \(g_{m}=\dbinom{n}{m}(2^{2^{n-m}}-1)\)

  • \(\begin{aligned} 2^{2^{n-m+1}}=2^{2^{n-m} \times 2}=2^{2^{n-m}+2^{n-m}}=(2^{2^{n-m}})^{2} \end{aligned}\) 倒序处理即可。

    点击查看代码
    const ll p=1000000007;
    ll g[1000010],jc[1000010],inv[1000010],jc_inv[1000010];
    ll C(ll n,ll m,ll p)
    {
        return (n>=m&&n>=0&&m>=0)?((jc[n]*jc_inv[m]%p)*jc_inv[n-m]%p):0;
    }
    int main()
    {
        ll n,k,i,mi=2,f=0;
        cin>>n>>k;
        inv[1]=1;
        jc[0]=jc_inv[0]=jc[1]=jc_inv[1]=1;
        for(i=2;i<=n;i++)
        {
            inv[i]=(p-p/i)*inv[p%i]%p;
            jc[i]=jc[i-1]*i%p;
            jc_inv[i]=jc_inv[i-1]*inv[i]%p;
        }	
        for(i=n;i>=k;i--)
        {
            g[i]=C(n,i,p)*mi%p;
            mi=mi*mi%p;
        }
        for(i=k;i<=n;i++)
        {
            f=(f+((i-k)%2==0?1:-1)*C(i,k,p)*g[i]%p+p)%p;
        }
        cout<<f<<endl;
        return 0;
    }
    

BZOJ3462 DZY Loves Math II

  • 因为有条件 \((2)\) 的限制,故条件 \((4)\) 成立的前提是对 \(S\) 的质因数分解后,不存在一个素数的指数 \(>1\)

  • 由算术基本定理,设 \(S=\sum\limits_{i=1}^{k}p_{i}^{c_{i}},n=\sum\limits_{i=1}^{k}p_{i}t_{i}\) ,其中 \(t_{i} \ge 1\)

  • 由于 \(n\) 很大,故直接完全背包无法维护。现让 \(n\) 减去 \(\sum\limits_{i=1}^{k}p_{i}\) ,此时只需要满足 \(t_{i} \ge 0\) 即可。

  • \(\begin{cases} x_{i}=\left\lfloor \frac{p_{i}t_{i}}{S} \right\rfloor \\ y_{i}=\frac{p_{i}t_{i} \bmod S}{p_{i}} \in [0,\frac{S}{p_{i}}) \end{cases}\) ,此时 \(p_{i}t_{i}\) 可以改写为 \(x_{i}S+y_{i}p_{i}\) ,即 \(\begin{aligned} n=\sum\limits_{i=1}^{k}x_{i}S+y_{i}p_{i}=S\sum\limits_{i=1}^{k}x_{i}+\sum\limits_{i=1}^{k}y_{i}p_{i} \end{aligned}\) ,其中 \(\sum\limits_{i=1}^{k}y_{i}p_{i}<kS\)

  • 接着考虑枚举 \(h \in [0,k)\) ,前半部分类似 luogu P1771 方程的解 ,方案数为 \(\dbinom{k+\left\lfloor \frac{n}{S} \right\rfloor-h-1}{k-1}\) ;后半部分由 \(\sum\limits_{i=1}^{k}y_{i}p_{i}=hS+n \bmod S\) 完全背包统计方案数即可。

    • 严格来说是后半部分不存在能拼成 \(S\) 的情况。
    点击查看代码
    const ll p=1000000007;
    ll prime[100],c[100],inv[100],f[12000010],len=0;
    void divide(ll n)
    {	
        for(ll i=2;i<=sqrt(n);i++)
        {
            if(n%i==0)
            {
                len++;
                prime[len]=i;
                c[len]=0;
                while(n%i==0)
                {
                    n/=i;
                    c[len]++;
                }
            }
        }
        if(n>1)
        {
            len++;
            prime[len]=n;
            c[len]=1;
        }
    }	
    ll C(ll n,ll m,ll p)
    {
        ll ans=1,i;
        if(n>=m&&n>=0&&m>=0)
        {
            for(i=n-m+1;i<=n;i++)
            {
                ans=ans*(i%p)%p;
            }
            for(i=1;i<=m;i++)
            {
                ans=ans*inv[i]%p;
            }
            return ans;
        }
        else
        {
            return 0;
        }
    }
    int main()
    {
        ll s,q,n,flag=1,sum=0,ans=0,i,j;
        cin>>s>>q;
        divide(s);
        f[0]=1;
        for(i=1;i<=len;i++)
        {
            flag&=(c[i]==1);
            sum+=prime[i];
            for(j=prime[i];j<=len*s;j++)	
            {
                f[j]=(f[j]+f[j-prime[i]])%p;
            }
            for(j=len*s;j>=s;j--)//减去影响
            {
                f[j]=(f[j]-f[j-s]+p)%p;
            }
        }
        inv[1]=1;
        for(i=2;i<=len;i++)
        {
            inv[i]=(p-p/i)*inv[p%i]%p;
        }
        for(i=1;i<=q;i++)
        {
            cin>>n;
            if(flag==0||sum>n)
            {
                cout<<"0"<<endl;
            }
            else
            {
                n-=sum;
                ans=0;
                for(j=0;j<=len-1&&j*s+n%s<=n;j++)
                {
                    ans=(ans+C(len+(n/s-j)-1,len-1,p)*f[j*s+n%s]%p)%p;
                }
                cout<<ans<<endl;
            }
        }
        return 0;
    }
    

5.24

闲话

做题纪要

5.25

闲话

做题纪要

CF1141E Superhero Battle

  • 等价于求一个最小的 \(m\) 使得 \(H+\sum\limits_{i=1}^{m}d_{(i-1) \bmod n+1} \le 0\) ,移项得到 \(\sum\limits_{i=1}^{m}-d_{(i-1) \bmod n+1} \ge H\)

  • \(\sum\limits_{i=1}^{m}-d_{(i-1) \bmod n+1}\) 拆成 \(x\sum\limits_{i=1}^{n}-d_{i}\)\(\sum\limits_{i=1}^{y}-d_{i}\) 两部分,即 \(m=xn+y\) 。枚举 \(y \in [1,n]\) ,则对应的 \(\min \{ x \}=\left\lceil \frac{H-\sum\limits_{i=1}^{y}-d_{i}}{\sum\limits_{i=1}^{n}-d_{i}} \right\rceil\)

  • 最终,有 \(\min\limits_{y=1}^{n} \{ \left\lceil \frac{H-\sum\limits_{i=1}^{y}-d_{i}}{\sum\limits_{i=1}^{n}-d_{i}} \right\rceil n+y \}\) 即为所求,注意精度影响,优化同 [ABC345B] Integer Division Returns

  • 注意判无解时要对第一轮进行特判。

    点击查看代码
    ll d[200010],sum[200010];
    int main()
    {
        ll h,n,ans=0x7f7f7f7f7f7f7f7f,flag=0,i;
        cin>>h>>n;
        for(i=1;i<=n;i++)
        {
            cin>>d[i];
            sum[i]=sum[i-1]-d[i];
            if(sum[i]>=h&&flag==0)
            {
                flag=1;
                cout<<i<<endl;
            }
        }
        if(flag==0)
        {
            if(sum[n]<=0)
            {
                cout<<"-1"<<endl;
            }
            else
            {
                for(i=1;i<=n;i++)
                {
                    ans=min(ans,(h-sum[i]+sum[n]-1)/sum[n]*n+i);
                }
                cout<<ans<<endl;
            }
        }
        return 0;
    }
    

luogu P3330 [ZJOI2011] 看电影

  • 由于只需要关注是否有人坐在位置上,故总方案数为 \(k^{n}\)

  • 接着开始考虑如何计算合法方案数。考虑拉链成环,在最后增加第 \(k+1\) 个座位,类似圆排的推导过程,有此时的方案数为 \(\frac{(k+1)^n}{k+1}=(k+1)^{n-1}\) 。但是 \(k+1\) 这个位置上是不能坐第 \(1 \sim n\) 个人的,可以强制让第 \(k+1\) 个位置上坐第 \(n+1\) 个人,且由于是环,故 \(k+1\) 这个位置在哪里并不重要,只需要找随便找一个位置即可,此时的方案数为 \(k+1-n\) 。二者相乘即可。

    • 为保证偶遇空位置,故 \(k+1-n \le 0\) 时无解。
  • 最终有 \(\dfrac{(k+1)^{n-1}(k+1-n)}{k^{n}}\) 即为所求。

    点击查看代码
    struct BigInteger
    {
        ll num[200];
        void init()
        {
            memset(num,0,sizeof(num));
            num[0]=1;
        }
        void print()
        {
            cout<<num[num[0]];
            for(ll i=num[0]-1;i>=1;i--)
            {
                printf("%08lld",num[i]);
            }
        }
        BigInteger operator * (ll another)
        {
            BigInteger ans;
            ans.init();
            ans.num[0]=num[0];
            for(ll i=1;i<=num[0];i++)
            {
                ans.num[i]+=num[i]*another;
                ans.num[i+1]+=ans.num[i]/100000000;
                ans.num[i]%=100000000;
            }
            while(ans.num[ans.num[0]+1]!=0)
            {
                ans.num[0]++;
            }
            return ans;
        }	
        BigInteger operator * (BigInteger another)
        {
            BigInteger ans;
            ans.init();
            ans.num[0]=num[0]+another.num[0]-1;
            for(ll i=1;i<=num[0];i++)
            {
                for(ll j=1;j<=another.num[0];j++)
                {
                    ans.num[i+j-1]+=num[i]*another.num[j];
                    ans.num[i+j-1+1]+=ans.num[i+j-1]/100000000;
                    ans.num[i+j-1]%=100000000;
                }
            }
            while(ans.num[ans.num[0]+1]!=0)
            {
                ans.num[0]++;
            }
            return ans;
        }	
        BigInteger operator / (ll another)
        {
            BigInteger ans;
            ans.init();
            ans.num[0]=num[0];
            for(ll i=1;i<=num[0];i++)
            {
                ans.num[i]=num[i];
            }
            for(ll i=num[0];i>=1;i--)
            {
                if(i-1>=1)
                {	
                    ans.num[i-1]+=ans.num[i]%another*100000000;
                }
                ans.num[i]/=another;
            }
            while(ans.num[0]>1&&ans.num[ans.num[0]]==0)
            {
                ans.num[0]--;
            }
            return ans;
        }
        ll operator % (ll another)
        {
            ll ans=0;
            for(ll i=num[0];i>=1;i--)
            {
                ans=(ans*100000000%another+num[i]%another)%another;
            }
            return ans;
        }
    }x,y;
    ll gcd(ll a,ll b)
    {
        return b?gcd(b,a%b):a;
    }
    BigInteger qpow(BigInteger a,ll b)
    {
        BigInteger ans;
        ans.init();
        ans.num[1]=1;
        while(b>0)
        {
            if(b&1)
            {
                ans=ans*a;
            }
            b>>=1;
            a=a*a;
        }
        return ans;
    }
    int main()
    {
        ll t,n,k,d,i;
        cin>>t;
        for(i=1;i<=t;i++)
        {
            cin>>n>>k;
            if(k+1-n<=0)
            {
                cout<<"0 1"<<endl;
            }
            else
            {
                x.init();
                y.init();
                x.num[1]=k+1;
                x=qpow(x,n-1);
                x=x*(k+1-n);
                y.num[1]=k;
                y=qpow(y,n);
                d=gcd(k+1-n,y%(k+1-n));
                x=x/d;
                y=y/d;
                x.print();
                cout<<" ";
                y.print();
                cout<<endl;
            }
        }
        return 0;
    }
    

HZOJ 571.摸鱼

  • 此时再 \(O(c)\) 枚举不太可做,考虑其他做法。

    • 虽然说数据过水,可以水过去。
  • 类似 CF1141E Superhero Battle ,我们仍将 \(m\) 拆成 \(m=x(c+d)+y\) 两部分,其中 \(y \le c\) 。由于前 \(c\) 项都是正整数,故从贪心的角度分析,在 \(y\) 大的同时 \(x\) 尽可能小即可,有 \(\left\lceil \frac{s-(a-b)c}{(a-b)c-bd} \right\rceil(c+d)+\left\lceil \frac{s-\left\lceil \frac{s-(a-b)c}{(a-b)c-bd} \right\rceil((a-b)c-bd)}{a-b} \right\rceil\) 即为所求。

  • 对第一轮进行特判。

    点击查看代码
    int main()
    {
        ll s,a,b,c,d,x,y,sum,ans;
        cin>>s>>a>>b>>c>>d;
        if((a-b)*c>=s)
        {
            ans=ceil(1.0*s/(a-b));
        }
        else
        {
            if(c*(a-b)-d*b<=0)
            {
                ans=-1;
            }
            else
            {
                sum=(a-b)*c-b*d;
                x=ceil(1.0*(s-(a-b)*c)/sum);
                y=ceil(1.0*(s-x*sum)/(a-b));
                ans=x*(c+d)+y;
            }
        }
        cout<<ans<<endl;
        return 0;
    }
    

5.26

闲话

做题纪要

[ABC350D] New Friends

  • 设一共有 \(k\) 个连通块,则 \(\sum\limits_{i=1}^{k}\frac{siz_{k}(siz_{k}-1)}{2}-m\) 即为所求。

    点击查看代码
    struct node
    {
        ll nxt,to;
    }e[400010];
    ll head[400010],vis[400010],cnt=0,num;
    void add(ll u,ll v)
    {
        cnt++;
        e[cnt].nxt=head[u];
        e[cnt].to=v;
        head[u]=cnt;
    }
    void dfs(ll x)
    {
        num++;
        vis[x]=1;
        for(ll i=head[x];i!=0;i=e[i].nxt)
        {
            if(vis[e[i].to]==0)
            {
                dfs(e[i].to);
            }
        }
    }
    int main()
    {
        ll n,m,u,v,sum=0,i;
        cin>>n>>m;
        for(i=1;i<=m;i++)
        {
            cin>>u>>v;
            add(u,v);
            add(v,u);
        }
        for(i=1;i<=n;i++)
        {
            if(vis[i]==0)
            {
                num=0;
                dfs(i);
                sum+=num*(num-1)/2;
            }
        }
        cout<<sum-m<<endl;
        return 0;
    }
    
posted @ 2024-05-21 15:49  hzoi_Shadow  阅读(61)  评论(3编辑  收藏  举报
扩大
缩小