【考试总结】2022-04-03
Max
设 表示 集合中的操作都选中了 且使其值变成了 的概率,平凡状压 即可
再计算 表示 集合选中了前 个元素且最大值是 的概率,枚举子集之后前缀和优化即可
当然可以子集卷积但是没必要
时间复杂度
Code Display
int f[42][1024][35];
int dp[42][1024][35];
int n,m,c;
int p[50][20][10];
int sum1[100],sum2[100];
signed main(){
freopen("max.in","r",stdin); freopen("max.out","w",stdout);
n=read(); m=read(); c=read();
for(int i=1;i<=m;++i) for(int j=1;j<=n;++j) for(int k=0;k<=c;++k) p[j][i][k]=read();
int S=1<<m;
for(int i=1;i<=n;++i){
f[i][0][0]=1;
for(int j=1;j<S;++j){
int lst=j-(j&(-j)),x=1+__builtin_ctzll(j&(-j));
for(int k=0;k<=m*c;++k) if(f[i][lst][k]){
rep(d,0,c) ckadd(f[i][j][k+d],mul(f[i][lst][k],p[i][x][d]));
}
}
}
dp[0][0][0]=1;
for(int i=1;i<=n;++i){
for(int s1=0;s1<S;++s1){
int T=(S-1)^s1;
for(int s2=T;s2;s2=(s2-1)&T){
sum1[0]=dp[i-1][s1][0];
sum2[0]=f[i][s2][0];
rep(h,1,m*c){
sum1[h]=add(sum1[h-1],dp[i-1][s1][h]);
sum2[h]=add(sum2[h-1],f[i][s2][h]);
}
ckadd(dp[i][s1^s2][0],mul(f[i][s2][0],dp[i-1][s1][0]));
rep(h,1,m*c){
dp[i][s1^s2][h]+=f[i][s2][h]*dp[i-1][s1][h]+sum1[h-1]*f[i][s2][h]+sum2[h-1]*dp[i-1][s1][h];
dp[i][s1^s2][h]%=mod;
}
}
}
for(int j=0;j<S;++j) for(int h=0;h<=m*c;++h) ckadd(dp[i][j][h],dp[i-1][j][h]);
}
int ans=0;
for(int i=1;i<=m*c;++i) ckadd(ans,mul(i,dp[n][S-1][i]));
print(ans);
return 0;
}
Paint
答案下界是 所以矩形一定跨过 或者 否则蜷缩在角上一定不优
以跨过 为例,枚举矩形的右边界并维护所有可能左边界的答案,这时对于每个左边的点其另一维边界就是它到当前枚举的边界中间区域 值大于其第一个点以及小于等于其第一个点对应的区间
可以使用单调栈配合线段树区间加法维护出最大合法区间长度,跨过另一维的处理方法是将两维坐标交换
Code Display
const int N=2e5+10;
int w,h,n;
pair<int,int> a[N];
int tag[N<<2],mx[N<<2];
#define ls p<<1
#define rs p<<1|1
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
inline void push_tag(int p,int v){tag[p]+=v; mx[p]+=v;}
inline void push_down(int p){
if(tag[p]){
push_tag(ls,tag[p]);
push_tag(rs,tag[p]);
tag[p]=0;
} return ;
}
inline void upd(int st,int ed,int v,int p=1,int l=1,int r=n){
if(st<=l&&r<=ed) return push_tag(p,v);
int mid=(l+r)>>1; push_down(p);
if(st<=mid) upd(st,ed,v,lson);
if(ed>mid) upd(st,ed,v,rson);
mx[p]=max(mx[ls],mx[rs]);
return ;
}
#undef ls
#undef rs
#undef lson
#undef rson
int ans=0;
inline void solve(){
memset(tag,0,sizeof(tag));
memset(mx,0,sizeof(mx));
sort(a+1,a+n+1);
static pair<int,int> stk1[N],stk2[N];
int top1=0,top2=0;
for(int i=1;i<=n;++i){
if(a[i].sec<=h/2){
int lst=i-1;
while(top1&&stk1[top1].sec<a[i].sec){
upd(stk1[top1].fir,lst,stk1[top1].sec-a[i].sec);
lst=stk1[top1--].fir-1;
}
if(lst!=i-1) stk1[++top1]={lst+1,a[i].sec};
}else{
int lst=i-1;
while(top2&&stk2[top2].sec>a[i].sec){
upd(stk2[top2].fir,lst,a[i].sec-stk2[top2].sec);
lst=stk2[top2--].fir-1;
}
if(lst!=i-1) stk2[++top2]={lst+1,a[i].sec};
}
stk1[++top1]={i,0};
stk2[++top2]={i,h};
upd(i,i,h-a[i].fir);
ckmax(ans,a[i+1].fir+mx[1]);
}
return ;
}
signed main(){
freopen("paint.in","r",stdin); freopen("paint.out","w",stdout);
w=read(); h=read();
n=read();
rep(i,1,n) a[i].fir=read(),a[i].sec=read();
a[++n]={0,0}; a[++n]={w,h};
solve();
for(int i=1;i<=n;++i) swap(a[i].fir,a[i].sec);
swap(w,h);
solve();
print(ans*2);
return 0;
}
Decompose
设 表示 所在的重链长度已经为 时 的子树内最大权值和,转移枚举找到一个儿子使其长度为 剩下的选 即可
那么变成了基础的 练习题,线段树 矩阵再用 std::set
维护轻儿子信息即可
Code Display
const int N=1e5+10,inf=1e18;
int n,Q,L,w[N][5],dp[N][5];
vector<int> G[N];
struct matrix{
int a[5][5]; matrix(){memset(a,-0x3f,sizeof(a));}
matrix operator *(const matrix &b) const{
matrix res;
rep(i,1,L) rep(k,1,L) rep(j,1,L) ckmax(res.a[i][j],a[i][k]+b.a[k][j]);
return res;
}
}t[N<<2],Bas;
int top[N],dfn[N],siz[N],ord[N],son[N],fa[N],dep[N],tim;
multiset<int> maxc[N][5];
int sumc[N],bot[N];
inline int Val(int v){return v<=-1e16?-inf:v;}
inline void dfs1(int x,int fat){
dep[x]=dep[fa[x]=fat]+(siz[x]=1);
for(auto t:G[x]){
dfs1(t,x); siz[x]+=siz[t];
if(siz[t]>siz[son[x]]) son[x]=t;
}
int sumf=0;
for(auto t:G[x]) sumf+=*max_element(dp[t]+1,dp[t]+L+1);
for(int i=1;i<=L;++i){
int Mx=-inf;
for(auto t:G[x]) ckmax(Mx,dp[t][i-1]-(*max_element(dp[t]+1,dp[t]+L+1)));
if(i==1) Mx=0;
dp[x][i]=sumf+w[x][i]+Mx;
}
return ;
}
inline void dfs2(int x,int topf){
top[x]=topf; ord[dfn[x]=++tim]=x;
bot[topf]=x;
if(son[x]) dfs2(son[x],topf);
for(auto t:G[x]) if(t!=son[x]){
dfs2(t,t);
rep(i,2,L) maxc[x][i].insert(Val(dp[t][i-1]-(*max_element(dp[t]+1,dp[t]+L+1))));
sumc[x]+=*max_element(dp[t]+1,dp[t]+L+1);
}
return ;
}
#define ls p<<1
#define rs p<<1|1
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
inline int Maxc(int x,int c){
if(!maxc[x][c].size()) return -inf;
return *prev(maxc[x][c].end());
}
inline void get_matrix(int p,int x){
for(int i=1;i<=L;++i){
for(int j=1;j<=L;++j){
t[p].a[i][j]=sumc[x]+w[x][j];
if(j!=1&&i!=j-1) t[p].a[i][j]+=Maxc(x,j);
}
} return ;
}
inline void build(int p,int l,int r){
if(l==r) return get_matrix(p,ord[l]);
int mid=(l+r)>>1;
build(p<<1,l,mid); build(p<<1|1,mid+1,r);
t[p]=t[p<<1|1]*t[p<<1];
}
inline void upd(int pos,int p=1,int l=1,int r=n){
if(l==r) return get_matrix(p,ord[l]);
int mid=(l+r)>>1;
if(pos<=mid) upd(pos,lson); else upd(pos,rson);
t[p]=t[p<<1|1]*t[p<<1];
return ;
}
inline matrix query(int st,int ed,int p=1,int l=1,int r=n){
if(st<=l&&r<=ed) return t[p];
int mid=(l+r)>>1;
if(ed<=mid) return query(st,ed,lson);
if(st>mid) return query(st,ed,rson);
return query(st,ed,rson)*query(st,ed,lson);
}
inline int get_dp(int x,int c=-1){
if(dep[bot[x]]-dep[x]+1<c) return -inf;
matrix res=bot[x]==x?Bas:query(dfn[x],dfn[bot[x]]-1);
if(~c) return w[bot[x]][1]+res.a[1][c];
int Mx=-inf;
for(int i=1;i<=L;++i) ckmax(Mx,res.a[1][i]);
return w[bot[x]][1]+Mx;
}
#undef ls
#undef rs
#undef lson
#undef rson
// Maintain sumc,maxc
inline void erase(int x){
while(top[x]!=1){
x=top[x];
matrix res=bot[x]==x?Bas:query(dfn[x],dfn[bot[x]]-1);
int Mx=-inf;
rep(i,1,L){
int val=Val(w[bot[x]][1]+res.a[1][i]);
ckmax(Mx,val);
}
rep(i,2,L){
int val=Val(w[bot[x]][1]+res.a[1][i-1]-Mx);
maxc[fa[x]][i].erase(maxc[fa[x]][i].find(val));
}
sumc[fa[x]]-=Mx;
x=fa[x];
} return ;
}
inline void insert(int x){
upd(dfn[x]);
while(top[x]!=1){
x=top[x];
matrix res=bot[x]==x?Bas:query(dfn[x],dfn[bot[x]]-1);
int Mx=-inf;
rep(i,1,L){
int val=Val(w[bot[x]][1]+res.a[1][i]);
ckmax(Mx,val);
}
rep(i,2,L){
int val=Val(w[bot[x]][1]+res.a[1][i-1]-Mx);
maxc[fa[x]][i].insert(val);
}
sumc[fa[x]]+=Mx;
upd(dfn[fa[x]]);
x=fa[x];
} return ;
}
signed main(){
freopen("decompose.in","r",stdin); freopen("decompose.out","w",stdout);
n=read(); Q=read(); L=read();
rep(i,2,n) G[fa[i]=read()].emplace_back(i);
for(int i=1;i<=n;++i){
rep(j,1,L) w[i][j]=read();
}
Bas.a[1][1]=0;
dfs1(1,0); dfs2(1,1); build(1,1,n);
while(Q--){
int x=read();
erase(x);
rep(i,1,L) w[x][i]=read();
insert(x);
print(get_dp(1));
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律