• [考试反思]0329省选模拟57:细节


    最近细节总是挂总是挂总是挂。我说我$T2$估分$62$有人信吗?

    有没有人信不重要。反正是没拿到。而且直接爆零了。

    原因是变量名写反了且少了一种情况(想到了忘写了)。这怕不是个弱智吧。。。

    大样例看起来挺大的,然后都跑过了,我以为不说$62$,$48$也应该是稳了。

    时间分配还是奇奇怪怪的,反正就是莫名的时间不够。

    $T2$研究了好久,$T3$也想了挺长时间。

    然后一直觉得$T1$很神仙(看数据范围不像什么常规的多项式复杂度$dp$,没往状压上想)于是最后只给它留了半小时左右。

    然后发现,好像出题人说它是签到题这是真的,于是就开始写,发现复杂度好像有点高(然而其实已经$AC$了)

    于是剩下的时间都拿去剪枝卡常什么的,再也没有看一眼我爆零的$T2...$

    改题的时候又自闭了。因为有下发数据于是一直没有写对拍,但是下发数据又太大,于是一直干瞪着。

    然后问别人也大都不给我看于是磨磨蹭蹭将近$6$小时就过去了。

    结果最后还是对拍小数据发现了问题,然后就$A$掉了。

    考后对拍也是真有用啊。。。

    T1:Max

    大意:初始为空的序列$A$长为$n$。$m$轮操作第$i$轮有$p_{i,j,k}$的概率使得$A_j + = k$。其中$0le k le c$

    求所有操作后整个序列最大值的期望。$n le 40,c'le 3 ,m le 10$

    数据范围小的奇怪。$m$在状压范围内。

    于是就状压$m$表示这个子集的轮是否已经被分配给其它人。做一个背包$dp$就行了。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define mod 1000000007
     4 int n,m,c,p[55][11][5],dp[1025][33],bp[1025][33],t[33],ans,bt[1025],pre[1025][33];
     5 int main(){//freopen("max3.in","r",stdin);
     6     cin>>n>>m>>c;
     7     for(int i=1;i<=m;++i)for(int j=1;j<=n;++j)for(int k=0;k<=c;++k)scanf("%d",&p[j][i][k]);
     8     const int mst=(1<<m)-1;
     9     for(int i=1;i<=mst;++i)bt[i]=bt[i^i&-i]+c;
    10     dp[mst][0]=1;
    11     for(int i=1;i<=n;++i){
    12         memset(bp,0,sizeof bp);memset(pre,0,sizeof pre);
    13         for(int s=mst;~s;--s){
    14             bp[s][0]=1;
    15             for(int j=1;j<=m;++j)if(s&1<<j-1){
    16                 for(int y=0;y<=bt[s];++y)for(int x=0;x<=c;++x)t[y+x]=(t[y+x]+1ll*bp[s][y]*p[i][j][x])%mod;
    17                 for(int y=0;y<=bt[s];++y)bp[s][y]=t[y],t[y]=0;
    18             }
    19             pre[s][0]=bp[s][0];
    20             for(int y=1;y<=bt[s];++y)pre[s][y]=(pre[s][y-1]+bp[s][y])%mod;
    21         }
    22         for(int s=1;s<=mst;++s)for(int x=0;x<=bt[mst^s];++x)if(dp[s][x])
    23             for(int u=s;u;u=u-1&s){
    24                 dp[s^u][x]=(dp[s^u][x]+1ll*dp[s][x]*pre[u][min(bt[u],x)])%mod;
    25                 for(int y=x+1;y<=bt[u];++y)dp[s^u][y]=(dp[s^u][y]+1ll*dp[s][x]*bp[u][y])%mod;
    26             }
    27     }for(int i=1;i<=bt[mst];++i)ans=(ans+1ll*i*dp[0][i])%mod; cout<<ans<<endl;
    28 }
    View Code

    T2:paint

    大意:$w imes h$的矩阵中有$n$特殊点,要求选定一个周长最大的矩形使得其内部不含特殊点(不含边框)。$nle 10^5,w,h le 10^8$

    发现任意一个$1 imes h$或$w imes 1$的矩形都一定合法。所以答案大于等于$(max(w,h)+1) imes 2$

    所以说它一定越过了$x=frac{x}{2}$或$y=frac{h}{2}$。以前者为例,做扫描线,枚举矩形右边界。

    用一个线段树维护每个点作为左端点的收益,即维护$max(-l+u-d)$。然后可以发现$u,d$的取值关于左端点单调,形式是单调栈。

    所以就这么维护一下,线段树区间加全局$max$。要注意各种边界。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define S 611111
     4 unordered_map<int,int>X; vector<int>Y[S];
     5 int n,w,h,ans,rx[S],x[S],y[S],u[S],ul[S],ut,d[S],dl[S],dt,v[S<<2],lz[S<<2],c,z,H;
     6 #define lc p<<1
     7 #define rc lc|1
     8 #define md (L+R>>1)
     9 void build(int p,int L,int R){lz[p]=0;
    10     if(L==R){v[p]=-rx[L];return;}
    11     build(lc,L,md); build(rc,md+1,R); v[p]=max(v[lc],v[rc]);
    12 }
    13 void add(int l,int r,int w,int p=1,int L=0,int R=c){if(r<l)return;//f(p==1)cerr<<l<<' '<<r<<' '<<w<<endl;
    14     if(l<=L&&R<=r){v[p]+=w;lz[p]+=w;return;}
    15     if(lz[p])v[lc]+=lz[p],v[rc]+=lz[p],lz[lc]+=lz[p],lz[rc]+=lz[p],lz[p]=0;
    16     if(l<=md)add(l,r,w,lc,L,md); if(r>md)add(l,r,w,rc,md+1,R); v[p]=max(v[lc],v[rc]);
    17 }
    18 void solve(){
    19     memset(rx,0,sizeof rx);
    20     H=h/2; n=z; X.clear();
    21     for(int i=1;i<=z;++i)rx[i]=x[i],x[++n]=x[i],y[n]=0,x[++n]=x[i],y[n]=h;
    22     x[++n]=w;y[n]=0; x[++n]=0;y[n]=0; x[++n]=0;y[n]=h; x[++n]=w;y[n]=h; rx[n-1]=0; rx[n]=w;
    23     sort(rx+1,rx+1+n); c=unique(rx+1,rx+1+n)-rx-1;
    24     for(int i=1;i<=c;++i)X[rx[i]]=i;
    25     for(int i=1;i<=n;++i)Y[X[x[i]]].push_back(y[i]);
    26     build(1,0,c); 
    27     u[0]=H; d[0]=H+1; ut=dt=0;
    28     for(int r=1;r<=c;++r){
    29         add(r-1,r-1,h);ans=max(ans,rx[r]+v[1]);add(r-1,r-1,-h);
    30         for(int a:Y[r])if(a<=H){
    31             if(dl[dt]==r&&d[dt]>=a)continue;
    32             while(d[dt]<=a)add(dl[dt-1],dl[dt]-1,d[dt]),dt--;
    33             add(dl[dt],r-1,-a);d[++dt]=a;dl[dt]=r;
    34         }else{
    35             if(ul[ut]==r&&u[ut]<=a)continue;
    36             while(u[ut]>=a)add(ul[ut-1],ul[ut]-1,-u[ut]),ut--;
    37             add(ul[ut],r-1,a);u[++ut]=a;ul[ut]=r;
    38         }Y[r].clear();
    39     }
    40 }
    41 int main(){
    42     cin>>w>>h>>n; z=n;
    43     for(int i=1;i<=z;++i)scanf("%d%d",&x[i],&y[i]);
    44     solve(); for(int i=1;i<=z;++i)swap(x[i],y[i]); swap(h,w); solve();
    45     cout<<ans*2<<endl;
    46 }
    View Code

    T3:Decompose

    大意:将树剖分成若干长度$le L$的链,对于每条链,其中深度第$i$大的点$p$会贡献$w[p][i]$。最大化整棵树的贡献。

    每次单点修改权值之后,进行回答。$n ,qL le 10^5,2 le L le 4$

    看一眼就知道是$ddp$。一如既往的难写。由于$T2$调太久了就没时间写了。

    首先暴力肯定就是$dp[p][i]=sumlimits_{u in son(p)} (maxlimits_{j=1}^{L} dp[u][j]) + maxlimits_{u in son(p)} (f[p][i-1] - (maxlimits_{j=1}^{L} dp[u][j]))$

    然后那个$max$可以用$set$维护。暴跳父亲复杂度是$O(n^2logn)$的。

    然后套个$ddp$的板子把上面这玩意轻重儿子分开弄一个矩阵,时间复杂度就变成$O(qlog^2nL^3+nL^3)$

    按照$dp$定义这里的矩阵当然是$max-add$矩阵。

    具体而言,考虑矩阵的构造,设$D[x]=egin{bmatrix} dp[x][1] \ dp[x][2] \ dp[x][3] \ dp[x][4] end{bmatrix}$。

    我们需要构造转移矩阵$T[x]$。使得$D[x]=T[x]D[hson[x]]$

    我们分情况讨论:对$dp[x][i]$产生贡献时,$i-1$是否来自$dp[hson[p]][i-1]$

    首先我们考虑轻儿子如何产生贡献:按照$dp$定义,答案就是所有儿子的$maxdp[son]$再去掉其中最小的$dp[son][i-1]-maxdp[son]$

    所以其中一部分就是$maxdp[son]$求和,这个可以直接拿数组维护,可以设$tot[i]$表示$i$的所有轻儿子的$maxdp$的和。每次修改轻儿子时直接减掉再加上新的就行。

    另一部分就是$dp[son][i-1]-maxdp[son]$。这个可以用一个$multiset$来维护。用的时候取出最大的。修改的时候直接$erase$旧的$insert$新的。

    所以可以设$maxc[i][j]$表示$i$的所有轻儿子的$dp[son][j-1]-maxdp[son]$的最小值。

    于是上面这些东西我们都可以看成常量了。我们考虑一条重链,如何构造矩阵。

    考虑矩阵的$(i,j)$元素。也就是说重儿子是链上第$j$个父亲是链上第$i$个。

    那么,如果有$i=j+1$那么也就是说重儿子已经可以接在链下面了,不必再付出其它代价,转移系数也就是矩阵元素是$w[fa][i]+tot[fa]$

    否则,就要从轻儿子里选择一个来做贡献,转移系数是$w[fa][i]+tot[fa]+maxc[fa][i]$

    这样就可以了。

    然后求一个点的$dp$值,其实就是查询从它到它所在重链的底端的点的矩阵的积,所得到的结果的第$L$列。

    每次修改的时候,把当前点的$dp$值更新,然后跳重链,每次遇到一条轻边,就更新重链链顶的$dp$,删掉原来的贡献并加上新的。

    树剖期望经过$log$次轻边。每次是一次线段树区间查询(只有一条重链),线段树单点修改(更新轻儿子贡献)。线段树上矩阵乘是$O(L^3logn)$的。

    所以总复杂度就是这样的。常数写丑了。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define S 111111
     4 #define ll long long
     5 #define inf 1000000000000000000
     6 multiset<ll>s[S][5]; vector<int>to[S];
     7 int n,q,L,f[S],sz[S],hson[S],tp[S],tl[S],ET,dfn[S],tim,idfn[S],w[S][5];
     8 ll tot[S],dp[S][5],mx[S];
     9 struct matrix{
    10     ll a[5][5];
    11     matrix operator*(matrix y){
    12         matrix z;
    13         for(int i=1;i<=L;++i)for(int j=1;j<=L;++j)z.a[i][j]=-inf;
    14         for(int i=1;i<=L;++i)for(int j=1;j<=L;++j)for(int k=1;k<=L;++k) z.a[i][j]=max(z.a[i][j],a[i][k]+y.a[k][j]);
    15         return z;
    16     }
    17 }v[S<<2],r;
    18 void dfs(int p){
    19     sz[p]=1; mx[p]=-inf;
    20     for(int i=2;i<=L;++i)s[p][i].insert(-inf); s[p][1].insert(0);
    21     for(int i=0,y;y=i<to[p].size()?to[p][i]:0;++i){
    22         dfs(y); sz[p]+=sz[y]; tot[p]+=mx[y];
    23         if(sz[y]>sz[hson[p]])hson[p]=y;
    24         for(int i=1;i<L;++i)s[p][i+1].insert(dp[y][i]-mx[y]);
    25     }for(int i=1;i<=L;++i)dp[p][i]=tot[p]+*s[p][i].rbegin()+w[p][i],mx[p]=max(mx[p],dp[p][i]);
    26 }
    27 void DFS(int p,int top){
    28     tp[p]=top; tl[top]=p; dfn[p]=++tim; idfn[tim]=p;
    29     if(hson[f[p]]==p){tot[f[p]]-=mx[p];for(int i=1;i<L;++i)s[f[p]][i+1].erase(s[f[p]][i+1].find(dp[p][i]-mx[p]));}
    30     if(hson[p])DFS(hson[p],top);
    31     for(int i=0,y;y=i<to[p].size()?to[p][i]:0;++i)if(y!=hson[p])DFS(y,y);
    32 }
    33 #define lc p<<1
    34 #define rc lc|1
    35 #define md (L+R>>1)
    36 matrix ask(int l,int r,int p=1,int L=1,int R=n){
    37     if(l<=L&&R<=r)return v[p];
    38     if(l<=md&&r>md)return ask(l,r,lc,L,md)*ask(l,r,rc,md+1,R);
    39     return l>md?ask(l,r,rc,md+1,R):ask(l,r,lc,L,md);
    40 }
    41 void chg(int P,int p=1,int L=1,int R=n){
    42     if(L==R){v[p]=r;return;}
    43     if(P<=md)chg(P,lc,L,md);else chg(P,rc,md+1,R); v[p]=v[lc]*v[rc];
    44 }
    45 void modify(int i){
    46     for(int j=1;j<=L;++j)for(int k=1;k<=L;++k)r.a[j][k]=w[i][j]+tot[i]+(j==k+1?0:*s[i][j].rbegin());
    47     chg(dfn[i]);
    48 }
    49 void get_dp(int p){
    50     r=ask(dfn[p],dfn[tl[p]]); mx[p]=-inf;
    51     for(int i=1;i<=L;++i)dp[p][i]=r.a[i][L],mx[p]=max(mx[p],dp[p][i]);
    52 }
    53 int main(){
    54     cin>>n>>q>>L;
    55     for(int i=2;i<=n;++i)scanf("%d",&f[i]),to[f[i]].push_back(i);
    56     for(int i=1;i<=n;++i)for(int j=1;j<=L;++j)scanf("%d",&w[i][j]);
    57     dfs(1); DFS(1,1);
    58     for(int i=1;i<=n;++i)modify(i);
    59     for(int i=1,p;i<=q;++i){
    60         scanf("%d",&p); for(int j=1;j<=L;++j)scanf("%d",&w[p][j]);
    61         modify(p); p=tp[p];
    62         while(p!=1){
    63             for(int i=1;i<L;++i)s[f[p]][i+1].erase(s[f[p]][i+1].find(dp[p][i]-mx[p])); tot[f[p]]-=mx[p];
    64             get_dp(p); 
    65             for(int i=1;i<L;++i)s[f[p]][i+1].insert(dp[p][i]-mx[p]); tot[f[p]]+=mx[p];
    66             modify(f[p]); p=tp[f[p]];
    67         }get_dp(1);    printf("%lld
    ",mx[1]);
    68     }
    69 }
    View Code
  • 相关阅读:
    园友五一快乐
    silverlight 2.0 入门教程(三)
    AJXA控件示例之   Accordion
    LINQ学习入门教程(一)
    泛型学习笔记
    梆定一个方法并把数据库中的值作为参数
    翻译IP地址转换成IP Number并得到国家
    vs 2005中解决找不到模板项
    silverlight 入门学习(二)
    最近的学习计划
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12595188.html
Copyright © 2020-2023  润新知