[考试反思]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$。其中$0\le 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\times h$的矩阵中有$n$特殊点,要求选定一个周长最大的矩形使得其内部不含特殊点(不含边框)。$n\le 10^5,w,h \le 10^8$

发现任意一个$1\times h$或$w \times 1$的矩形都一定合法。所以答案大于等于$(max(w,h)+1)\times 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]=\sum\limits_{u \in son(p)} (\max\limits_{j=1}^{L} dp[u][j]) + \max\limits_{u \in son(p)} (f[p][i-1] - (\max\limits_{j=1}^{L} dp[u][j]))$

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

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

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

具体而言,考虑矩阵的构造,设$D[x]=\begin{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\n",mx[1]);
68     }
69 }
View Code

 

posted @ 2020-03-30 07:29  DeepinC  阅读(...)  评论(...编辑  收藏