• 【考试总结】20220406


    Fable

    考虑冒泡排序的性质即如果某个数前面有元素大于之,那么一定在这轮这种元素数量恰好减少 \(1\)

    那么可以计算出来经过 \(k\) 轮后的每个位置的数字前面有几个元素大于之,然后使用数据结构维护最小的前方没有元素大于之的数即可

    这样子的数据结构需要支持区间减法,所以写了线段树

    Code Display
    const int N=200010;
    int n,m,a[N],k,b[N];
    struct Fenwick{
        int c[N];
        inline int query(int x){
            int res=0;
            for(;x<=m;x+=x&(-x)) res+=c[x];
            return res;
        }
        inline void insert(int x,int v){
            for(;x;x-=x&(-x)) c[x]++;
            return ;
        }
    }T;
    int lsh[N];
    bool vis[N];
    vector<int> inv[N];
    struct Seg{
        int Mn[N<<2],tag[N<<2];
        inline void push_tag(int p,int v){Mn[p]+=v; tag[p]+=v;}
        inline void push_down(int p){
            if(tag[p]){
                push_tag(p<<1,tag[p]);
                push_tag(p<<1|1,tag[p]);
                tag[p]=0;
            } return ;
        }
        inline void push_up(int p){
            Mn[p]=min(Mn[p<<1],Mn[p<<1|1]);
            return ;
        }
        inline void build(int p,int l,int r){
            if(l==r){
                Mn[p]=inv[l].back();
                return ;
            }
            int mid=(l+r)>>1;
            build(p<<1,l,mid); build(p<<1|1,mid+1,r);
            return push_up(p);
        }
        inline void upd(int p,int l,int r,int st,int ed){ 
            if(st<=l&&r<=ed) return push_tag(p,-1);
            int mid=(l+r)>>1; push_down(p);
            upd(p<<1,l,mid,st,ed);
            if(ed>mid) upd(p<<1|1,mid+1,r,st,ed);
            return push_up(p);
        }
        inline int dfs(int p,int l,int r){
            if(l==r){
                inv[l].pop_back();
                Mn[p]=inv[l].size()?inv[l].back()+tag[p]:n+1;
                return l;
            }
            int mid=(l+r)>>1,res=0;
            push_down(p);
            if(Mn[p<<1]==0) res=dfs(p<<1,l,mid);
            else res=dfs(p<<1|1,mid+1,r);
            push_up(p);
            return res;
        }
    }seg;
    signed main(){
        freopen("fable.in","r",stdin); freopen("fable.out","w",stdout);
        n=read(); k=read();
        rep(i,1,n) a[i]=read(),lsh[i]=a[i];
        sort(lsh+1,lsh+n+1);
        m=unique(lsh+1,lsh+n+1)-lsh-1;
        rep(i,1,n){
            a[i]=lower_bound(lsh+1,lsh+m+1,a[i])-lsh;
            b[i]=T.query(a[i]+1);
            T.insert(a[i],1);
        }
        rep(i,1,n){
            b[i]=max(0ll,b[i]-k);
            inv[a[i]].emplace_back(b[i]);
        }
        rep(i,1,m){
            sort(inv[i].begin(),inv[i].end());
            reverse(inv[i].begin(),inv[i].end());
        }
        seg.build(1,1,m);
        rep(i,1,n){
            int v=seg.dfs(1,1,m);
            print(lsh[v]);
            if(v>1) seg.upd(1,1,m,1,v-1);
        }
        return 0;
    }
    

    Fiend

    逆序对奇数减,偶数加,符合行列式定义,平凡做法就是直接求行列式 \(A_{i,l_i\sim r_i}=1\) 的值

    但是发现每行的 \(1\) 是连续的,可以对于每列找到所有这列有元的行中右端点最小的,并将其它的行 \(l_j\leftarrow r_i+1\)

    如果需要交换行那么需要将行列式的值取反

    那么使用左偏树维护所有的左端点,要支持的操作是取出堆顶,合并两个堆

    同时在左偏树的每个节点维护点对应的行编号以及逆映射,交换两行时就能维护正确的行号了

    Code Display
    const int N=1e5+10;
    int n,nds;
    int rt[N],ls[N],rs[N],dep[N],mp[N],id[N],val[N];
    inline int merge(int x,int y){
        if(!x||!y) return x+y;
        if(val[x]>val[y]) swap(x,y);
        rs[x]=merge(rs[x],y);
        if(dep[rs[x]]>dep[ls[x]]) swap(ls[x],rs[x]);
        dep[x]=dep[rs[x]]+1;
        return x;
    }
    inline void pop(int &x){x=merge(ls[x],rs[x]);}
    inline int New(int v,int lin){
        int p=++nds;
        mp[lin]=p; id[p]=lin;
        dep[p]=1;
        val[p]=v;
        return p;
    }
    signed main(){
        freopen("fiend.in","r",stdin); freopen("fiend.out","w",stdout);
        int T=read(); while(T--){
            n=read();
            for(int i=1;i<=n;++i){
                int l=read(),r=read();
                rt[l]=merge(rt[l],New(r,i));
            }
            int ans=1;
            for(int i=1;i<=n;++i){
                if(!rt[i]){ans=0; break;}
                if(id[rt[i]]!=i){
                    id[mp[i]]=id[rt[i]];
                    mp[id[rt[i]]]=mp[i];
                    ans*=-1;
                }
                int v=val[rt[i]];
                pop(rt[i]);
                if(val[rt[i]]==v){ans=0; break;}
                if(v<n) rt[v+1]=merge(rt[v+1],rt[i]);
            }
            if(ans>0) puts("Y");
            else if(ans==0) puts("D");
            else puts("F");
            for(int i=1;i<=n;++i){
                dep[i]=ls[i]=rs[i]=val[i]=0;
                id[i]=mp[i]=0;
                rt[i]=0;
            }
            nds=0;
        }
        return 0;
    }
    

    Flair

    使用互质数对 \((a,b)\) 不能表示出来的最大数是 \(ab-a-b\) 推导不互质的数对可以发现:在 \(x>10000\) 后,每个菜品数量所消耗的钱数是每 \(\rm GCD\{c\}\) 一循环的,同时在每个循环节中都是以 \(\rm GCD-1\to 0\) 方式递减

    那么使用倍增 \(\rm MTT\) 配合 \(f_{i,j}=pf_{i-1,j-1}+(1-p)f_{i,j}\) 计算 \(G_r=\sum\limits_{i\equiv r\bmod\ {\rm{GCD}}} f_{n,i}\) 后可以得到选择菜品数较多时候的答案

    对于选择菜品数对应的浪费的钱数未进入循环节的情况,可以另做一个背包来算浪费数,而对应的选菜概率的计算可以使用 组合数等于下降幂除阶乘 的方式来解决

    Code Display
    const int N=10010;
    int n,m,p,c[N];
    const double pi=acos(-1);
    struct node{
        long double x,y;
        node(){}
        node(long double xx,long double yy){x=xx; y=yy; return ;}
        node operator +(const node &a)const{return node(x+a.x,y+a.y);}
        node operator -(const node &a)const{return node(x-a.x,y-a.y);}
        node operator *(const node &a)const{return node(x*a.x-y*a.y,x*a.y+y*a.x);}
        inline node conj(){return node(x,-y);}
        inline void clear(){x=y=0;}
    }A0[N<<2],B0[N<<2],A1[N<<2],B1[N<<2],W[N<<2],F[N<<2],G[N<<2],H[N<<2];
    int r[N<<2];
    inline void FFT(node *f,int lim,int opt){
    	rep(i,0,lim-1){
            if(i<r[i]) swap(f[i],f[r[i]]);
        }
        for(int p=2;p<=lim;p<<=1){
    	    int len=p>>1; node tt;
            W[0]=node(1,0); 
            rep(i,1,len-1) W[i]=node(cos(pi/len*i),opt*sin(pi/len*i));
    	    for(int k=0;k<lim;k+=p){
                for(int l=k;l<k+len;++l){
                    tt=f[l+len]*W[l-k];
                    f[len+l]=f[l]-tt,f[l]=f[l]+tt;
                }
            }
        }
        if(opt==-1) rep(i,0,lim-1) f[i].x/=lim;
    }
    int poly[N],bas[N],g;
    inline void MTT(int *a,int *b,int *res,int n,int m){
        int lim=1; while(lim<=(n+m)) lim<<=1;
        rep(i,0,lim-1){
            A0[i].x=A0[i].y=0;
            B1[i].x=B1[i].y=0;
            B0[i].x=B0[i].y=0;
            A1[i].x=A1[i].y=0;
            H[i].x=H[i].y=0;
            G[i].x=G[i].y=0;
            F[i].x=F[i].y=0;
            r[i]=r[i>>1]>>1|((i&1)?(lim>>1):0);
        }
        for(int i=0;i<n;++i) A0[i].x=a[i]>>15,A0[i].y=a[i]&32767; FFT(A0,lim,1);
        for(int i=0;i<m;++i) B0[i].x=b[i]>>15,B0[i].y=b[i]&32767; FFT(B0,lim,1);
        for(int i=0;i<lim;++i) A1[i]=A0[i?lim-i:0].conj(),B1[i]=B0[i?lim-i:0].conj();
        node p,q;
        for(int i=0;i<lim;++i){
            p=A0[i],q=A1[i];
            A0[i]=(p+q)*node(0.5,0),A1[i]=(q-p)*node(0,0.5); 
            p=B0[i],q=B1[i]; 
            B0[i]=(p+q)*node(0.5,0),B1[i]=(q-p)*node(0,0.5);
            F[i]=A0[i]*B0[i]*node(1,0); 
            G[i]=A0[i]*B1[i]*node(1,0)+A1[i]*B0[i]*node(1,0);
            H[i]=A1[i]*B1[i]*node(1,0);
        }
        FFT(F,lim,-1); FFT(G,lim,-1); FFT(H,lim,-1); 
        int up=min(g,n+m-1);
        rep(i,0,up-1) res[i]=0;
        for(int i=0;i<lim;++i) res[i%g]+=(int)(F[i].x+0.5)%mod*((1<<30)%mod)%mod+(int)(G[i].x+0.5)%mod*(1<<15)%mod+(int)(H[i].x+0.5)%mod; 
        for(int i=0;i<up;++i) res[i]=(res[i]%mod+mod)%mod;
    }
    int ifac[N];
    signed main(){
        freopen("flair.in","r",stdin); freopen("flair.out","w",stdout);
        n=1e4; ifac[0]=1;
        for(int i=1;i<=n;++i) ifac[i]=mul(ifac[i-1],ksm(i,mod-2));
        int T=read(); while(T--){
            n=read(); m=read(); p=read();
            g=-1;
            rep(i,1,m) g=g==-1?c[i]=read():__gcd(g,c[i]=read());
            sort(c+1,c+m+1);
            vector<int> dp(20010,1000100);
            dp[0]=0;
            int up=2e4;
            for(int i=1;i<=m;++i){
                for(int j=0;j+c[i]<=up;++j) if(dp[j]==0) dp[j+c[i]]=0;
            }
            for(int i=up-1;i>=0;--i) ckmin(dp[i],dp[i+1]+1);
            rep(i,0,g-1) poly[i]=bas[i]=0;
            poly[0]=1;
            bas[1]=p; bas[0]=100-p;
            int y=n,lenb=2,lenp=1;
            while(y){
                if(y&1){
                    MTT(poly,bas,poly,lenp,lenb);
                    lenp=min(g,lenp+lenb-1);
                }
                MTT(bas,bas,bas,lenb,lenb);
                lenb=min(g,lenb*2-1);
                y>>=1;
            }
            int ans=0;
            int dfac=1,pwp=1,curpw=ksm(100-p,n),Inv=ksm(100-p,mod-2);
            for(int i=0;i<=min(n,10000ll);++i){
                int contr=mul(mul(pwp,curpw),mul(dfac,ifac[i]));
                ckadd(ans,mul(dp[i],contr));
                ckdel(poly[i%g],contr);
                ckmul(dfac,n-i);
                ckmul(pwp,p);
                ckmul(curpw,Inv);
            }
            for(int i=1;i<g;++i) ckadd(ans,mul(poly[i],g-i));
            print(ans);
        }
        return 0;
    }
    

  • 相关阅读:
    JS DOM编程艺术——DOM获取元素—— JS学习笔记2015-7-6(第77天)
    JS DOM编程艺术的学习—— JS学习笔记2015-7-5(第76天)
    面向对象的程序设计1 理解对象—— JS学习笔记2015-7-4(第75天)
    JS 引用类型 Math 对象 JS学习笔记2015-7-3(第74天)
    JS 引用类型和值类型
    HTML5之应用缓存---manifest---缓存使用----Web前端manifest缓存
    易懂 易上手的cookie 最简单明了 js中cookie的使用方法及教程
    iOS开发-面试总结(十一)
    iOS开发-面试总结(十)
    iOS开发-面试总结(九)
  • 原文地址:https://www.cnblogs.com/yspm/p/16107759.html
Copyright © 2020-2023  润新知