zoukankan      html  css  js  c++  java
  • [题解] 杂题记录(2021/10/30)

    IOI2018 Meetings

    题目

    链接

    简答

    设状态 (f_{i,j}) 表示区间 (left[i,j ight]) 的最小代价,那么朴素区间dp是 (mathcal{O}left(n^2 ight))

    考虑建出这个序列的笛卡尔树,然后处理到节点 (u) 时,假设它是区间 (left[l,r ight]) 里的最大值,那么考虑建两棵线段树,维护 (f_{l,u-1},f_{l+1,u-1}cdots f_{u-1,u-1},f_{u+1,r},f_{u+2,r}cdots f_{r,r}) 以及 (f_{l,l},f_{l,l+1}cdots f_{l,u-1},f_{u+1,u+1},f_{u+1,u+2}cdots f_{u+1,r})

    对于一个区间 (left[l,r ight]) ,设 (u=operatorname{LCA}left(l,r ight)) ,那么当决策点 (le u) 时 ,(u,u+1,cdots r) 的代价都是 (v_u) ,当决策点 (ge u) 时,(l,l+1,cdots u) 的代价也都是 (v_u)

    考虑如何快速从 (u) 转移到 (fa_u)

    假设 (u)(v=fa_u) 的左子树 ,(u) 代表的区间是 (left[l,v-1 ight])(v) 代表的区间是 (left[l,r ight])

    那么 (f_{k,v-1} ightarrow minleft(f_{k,u-1}+left(v-u ight)v_u,f_{u+1,v-1}+left(u-k+1 ight)v_u ight)) ,其余同理,即线段树上加等差数列,区间取最小值

    由于 (f_{k,v-1}) 是单调的,所以直接线段树上二分即可

    代码

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <vector>
    #include <tuple>
    using namespace std;
    typedef long long ll;
    constexpr int N=750010;
    struct segT{
        ll tgadd[N<<2],tgarr[N<<2][2],fst[N<<2],lst[N<<2];
        bool hag[N<<2],harg[N<<2];
        void updarr(int u,ll n1,ll n2,int l,int r){harg[u]=true,hag[u]=false,tgadd[u]=0;fst[u]=n1,lst[u]=n1+n2*(r-l);tgarr[u][0]=n1,tgarr[u][1]=n2;}
        void updadd(int u,ll n1){hag[u]=true;fst[u]+=n1,lst[u]+=n1,tgadd[u]+=n1;}
        void pushdown(int u,int l,int r){
            if(l==r) return;int mid=(l+r)>>1;
            if(harg[u]) updarr(u<<1,tgarr[u][0],tgarr[u][1],l,mid),updarr(u<<1|1,tgarr[u][0]+tgarr[u][1]*(mid-l+1),tgarr[u][1],mid+1,r),harg[u]=false;
            if(hag[u]) updadd(u<<1,tgadd[u]),updadd(u<<1|1,tgadd[u]),hag[u]=false,tgadd[u]=0;
        }
        void segadd(int u,int cl,int cr,int ql,int qr,ll val){
            pushdown(u,cl,cr);if(cl>=ql && cr<=qr){updadd(u,val);return;}int mid=(cl+cr)>>1;
            if(ql<=mid) segadd(u<<1,cl,mid,ql,qr,val);if(qr>mid) segadd(u<<1|1,mid+1,cr,ql,qr,val);fst[u]=fst[u<<1],lst[u]=lst[u<<1|1];
        }
        void segarr(int u,int cl,int cr,int ql,int qr,ll val1,ll val2){
            pushdown(u,cl,cr);if(cl>=ql && cr<=qr){updarr(u,val1+(cl-ql)*val2,val2,cl,cr);return;}int mid=(cl+cr)>>1;
            if(ql<=mid) segarr(u<<1,cl,mid,ql,qr,val1,val2);if(qr>mid) segarr(u<<1|1,mid+1,cr,ql,qr,val1,val2);fst[u]=fst[u<<1],lst[u]=lst[u<<1|1];
        }
        ll query_s(int u,int cl,int cr,int pos){pushdown(u,cl,cr);if(cl==cr) return fst[u];int mid=(cl+cr)>>1;return pos<=mid?query_s(u<<1,cl,mid,pos):query_s(u<<1|1,mid+1,cr,pos);}
        void upd_left(int u,int cl,int cr,int ql,int qr,ll val1,ll val2){
            pushdown(u,cl,cr);int mid=(cl+cr)>>1;
            if(cl>=ql && cr<=qr){
                ll st=(cl-ql)*val2+val1,ed=(cr-ql)*val2+val1;
                if(lst[u]>ed && fst[u]>st) updarr(u,st,val2,cl,cr);
                else if(fst[u]>st) upd_left(u<<1,cl,mid,ql,qr,val1,val2),upd_left(u<<1|1,mid+1,cr,ql,qr,val1,val2),fst[u]=fst[u<<1],lst[u]=lst[u<<1|1];
                return;
            }
            if(ql<=mid) upd_left(u<<1,cl,mid,ql,qr,val1,val2);if(qr>mid) upd_left(u<<1|1,mid+1,cr,ql,qr,val1,val2);fst[u]=fst[u<<1],lst[u]=lst[u<<1|1];
        }
        void upd_right(int u,int cl,int cr,int ql,int qr,ll val1,ll val2){
            pushdown(u,cl,cr);int mid=(cl+cr)>>1;
            if(cl>=ql && cr<=qr){
                ll st=(cl-ql)*val2+val1,ed=(cr-ql)*val2+val1;
                if(lst[u]>ed && fst[u]>st) updarr(u,st,val2,cl,cr);
                else if(lst[u]>ed) upd_right(u<<1,cl,mid,ql,qr,val1,val2),upd_right(u<<1|1,mid+1,cr,ql,qr,val1,val2),fst[u]=fst[u<<1],lst[u]=lst[u<<1|1];
                return;
            }
            if(ql<=mid) upd_right(u<<1,cl,mid,ql,qr,val1,val2);if(qr>mid) upd_right(u<<1|1,mid+1,cr,ql,qr,val1,val2);fst[u]=fst[u<<1],lst[u]=lst[u<<1|1];
        }
    }TL,TR;//TL from left to right, TR from right to left
    int stk[N],arr[N],ch[N][2],stktop,n,q,son[N],top[N],dep[N],fa[N];
    void dfs1(int u,int ff,int dp,int l,int r,int tp){
        dep[u]=dp,son[u]=((u-l)>(r-u))?ch[u][0]:ch[u][1],top[u]=tp,fa[u]=ff;
        if(ch[u][0]) dfs1(ch[u][0],u,dp+1,l,u-1,(ch[u][0]==son[u])?tp:ch[u][0]);
        if(ch[u][1]) dfs1(ch[u][1],u,dp+1,u+1,r,(ch[u][1]==son[u])?tp:ch[u][1]);
        // printf("%d %d %d %d %d
    ",u,ch[u][0],ch[u][1],dep[u],top[u]);
    }
    int lca(int u,int v){
        while(top[u]!=top[v]){
            if(dep[top[u]]<dep[top[v]]) swap(u,v);
            u=fa[top[u]];
        }
        return dep[u]>dep[v]?v:u;
    }
    vector<tuple<int,int,int> > qrys[N];ll ans[N];
    void dfs_calc(int u,int l,int r){
        if(ch[u][0]) dfs_calc(ch[u][0],l,u-1);if(ch[u][1]) dfs_calc(ch[u][1],u+1,r);
        if(ch[u][0]){
            int v=ch[u][0];TL.segadd(1,1,n,v,u-1,1ll*arr[v]*(v-l+1));TR.segadd(1,1,n,l,v,1ll*arr[v]*(u-v));
            ll vall=((l<v)?TL.query_s(1,1,n,v-1):0),valr=((v<u-1)?TR.query_s(1,1,n,v+1):0);
            TL.upd_left(1,1,n,v,u-1,vall+arr[v],arr[v]);TR.upd_right(1,1,n,l,v,valr+1ll*arr[v]*(v-l+1),-arr[v]);
            // printf("left %d %d %d
    ",u,l,r);
            // for(int i=1;i<=n;++i) printf("(%lld,%lld) ",TL.query_s(1,1,n,i),TR.query_s(1,1,n,i));printf("
    ");
        }
        if(ch[u][1]){
            int v=ch[u][1];TL.segadd(1,1,n,v,r,1ll*arr[v]*(v-u));TR.segadd(1,1,n,u+1,v,1ll*arr[v]*(r-v+1));
            ll vall=((u+1<v)?TL.query_s(1,1,n,v-1):0),valr=((v<r)?TR.query_s(1,1,n,v+1):0);
            TL.upd_left(1,1,n,v,r,vall+arr[v],arr[v]);TR.upd_right(1,1,n,u+1,v,valr+1ll*arr[v]*(v-u),-arr[v]);
        }
        // printf("%d %d %d
    ",u,l,r);
        // for(int i=1;i<=n;++i) printf("(%lld,%lld) ",TL.query_s(1,1,n,i),TR.query_s(1,1,n,i));printf("
    ");
        for(auto qry:qrys[u]) ans[get<2>(qry)]=min(1ll*arr[u]*(get<1>(qry)-u+1)+TR.query_s(1,1,n,get<0>(qry)),1ll*arr[u]*(u-get<0>(qry)+1)+TL.query_s(1,1,n,get<1>(qry)));
    }
    int main(){
        // freopen("meetings.in","r",stdin);
        scanf("%d %d",&n,&q);for(int i=1;i<=n;++i) scanf("%d",&arr[i]);
        stk[++stktop]=1;
        for(int i=2;i<=n;++i){
            while(stktop && arr[stk[stktop]]<arr[i]) ch[i][0]=stk[stktop],--stktop;
            if(stktop) ch[stk[stktop]][1]=i;stk[++stktop]=i;
        }
        dfs1(stk[1],0,1,1,n,stk[1]);
        for(int i=1,l,r;i<=q;++i) scanf("%d %d",&l,&r),++l,++r,qrys[lca(l,r)].push_back(make_tuple(l,r,i))/*,printf("%d
    ",lca(l,r))*/;
        dfs_calc(stk[1],1,n);
        for(int i=1;i<=q;++i) printf("%lld
    ",ans[i]);
        return 0;
    }
    

    CF1326F Wise Men

    题目

    链接

    简答

    这题不会做,观察题解的

    考虑把 (0) 的限制去掉然后容斥。

    先状压dp计算出 (f_{S}) ,表示一段连续的长度为 (left|S ight|) 的 1,且点集为 (S) 的路径的方案数

    然后直接暴力枚举 (n) 的划分作为每一段 (1) 的长度,(FWT) 卷积即可

    注意到此时 (sumleft| S ight| = n) ,所以直接取 (FWT)(x_{left[n ight]}) 的系数即可保证 (cup S=left[n ight]) ,且任意两个集合交集为空

    代码

    #include <cstdio>
    #include <algorithm>
    #include <vector>
    #include <map>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    constexpr int N=18;
    map<vector<int>,int> ans;
    int n,cnt;ll pre[N+1][(1<<N)+N],f[N][(1<<N)+N];
    bool mp[N+1][N+1];char s[N+1];
    vector<int> nums[N+1];
    vector<int> cur;
    vector<int> mm[2010];
    ll fnl[(1<<N)+N],tmp[(1<<N)+N];
    void fwt(ll *p,int len,int V){for(int l=2;l<=len;l<<=1) for(int mid=l>>1,j=0;j<len;j+=l) for(int i=0;i<mid;++i) p[i+j+mid]+=V*p[i+j];}
    void dfs(int pos,int sum){
        if(!pos){if(sum==n) ++cnt,ans[cur]=cnt;return;}
        int lim=(n-sum)/pos;
        for(int i=0;i<=lim;++i) dfs(pos-1,sum+i*pos),cur.push_back(pos);
        for(int i=lim;i>=0;--i) cur.pop_back();
    }
    ll darr[(1<<N)+N];
    ll st[N+1][(1<<N)+N];
    void dfs2(int pos,int sum){
        if(!pos){if(sum==n){int idx=ans[cur];memcpy(tmp,darr,sizeof(tmp));fwt(tmp,(1<<n),-1);/*for(int i=0;i<(1<<n);++i) printf("%lld ",tmp[i]);printf("
    ");*/
        for(int val:mm[idx]) fnl[val]=tmp[(1<<n)-1];}return;}
        int lim=(n-sum)/pos;
        dfs2(pos-1,sum);
        if(lim>=1){
            memcpy(st[pos],darr,sizeof(st[pos]));
            for(int i=1;i<=lim;++i){
                for(int j=0;j<(1<<n);++j) darr[j]*=pre[pos][j];cur.push_back(pos);
                dfs2(pos-1,sum+i*pos);
            }
            memcpy(darr,st[pos],sizeof(darr));for(int i=lim;i;--i) cur.pop_back();
        }
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;++i){
            scanf("%s",s+1);
            for(int j=1;j<=n;++j) mp[i][j]=(s[j]-'0')==1;
        }
        for(int i=1;i<=n;++i) f[i][1<<(i-1)]=1;
        for(int i=1;i<(1<<n);++i) nums[__builtin_popcount(i)].push_back(i);
        for(int k=1;k<=n;++k) for(int val:nums[k])
        for(int i=1;i<=n;++i) if((val>>(i-1))&1) for(int j=1;j<=n;++j) if((val>>(j-1))&1 && i!=j && mp[i][j]) f[i][val]+=f[j][val^(1<<(i-1))];
        // for(int i=1;i<=n;++i){printf("%d:
    ",i);for(int j=0;j<(1<<n);++j) printf("%lld ",f[i][j]);printf("
    ");}
        for(int i=1;i<=n;++i){for(int val:nums[i]) for(int j=1;j<=n;++j) pre[i][val]+=f[j][val];
        fwt(pre[i],(1<<n),1);/*printf("%d:
    ",i);for(int j=0;j<(1<<n);++j) printf("%lld ",pre[i][j]);printf("
    ");*/}
        dfs(n,0);vector<int> dc;
        // printf("%d
    ",cnt);
        for(int i=0;i<(1<<(n-1));++i){
            dc.clear();for(int j=0,ct=1;j<n;++j){if((i>>j)&1) ++ct;else dc.push_back(ct),ct=1;}
            sort(dc.begin(),dc.end(),[](auto a,auto b){return a>b;});
            mm[ans[dc]].push_back(i);
            // printf("%d %d
    ",i,ans[dc]);
        }
        for(int i=0;i<(1<<n);++i) darr[i]=1;
        dfs2(n,0);//for(int i=0;i<(1<<(n-1));++i) printf("%lld ",fnl[i]);printf("
    ");
        reverse(fnl,fnl+(1<<(n-1)));fwt(fnl,(1<<(n-1)),-1);reverse(fnl,fnl+(1<<(n-1)));
        for(int i=0;i<(1<<(n-1));++i) printf("%lld ",fnl[i]);printf("
    ");
        return 0;
    }
    
  • 相关阅读:
    (转)Java中金钱的类的计算
    (转)如何实现删除重复记录并且只保留一条?
    MAXIMO-IBM文件夹的笔记
    maximo功能修改笔记
    maximo功能修改(初步理解)
    如何将两张表查询的结果集和下一张表查询
    Birt 折腾一周总结
    一天天的sql总结
    maximo弹框设置新的功能测试总结
    关于对 maximio平台的五个常用类的初步理解及总结
  • 原文地址:https://www.cnblogs.com/aixiaoyaowudi/p/15484882.html
Copyright © 2011-2022 走看看