2022/3/20 DP专场总结
简单说,\(\LARGE 我颓了\)。
A.棋盘分割
- 二维区间DP
但讲真的有人能看出来吗;
B.Tree with Max Cost
- 换根树形DP板子……(然而并没有写);
AC code
#include<iostream>
#include<ios>
#include<cstring>
#include<cmath>
using namespace std;
const int N=2e5+10;
int n;
int a[N];
long long dist[N];
int head[N],ver[N<<1],nxt[N<<1],tot=0;
long long cnt,ans;
void add(int x,int y){
ver[++tot]=y,nxt[tot]=head[x],head[x]=tot;
return ;
}
void count(int x,int fr,int dep){
cnt+=1ll*dep*a[x];
dist[x]=a[x];
for(int i=head[x];i;i=nxt[i]){
if(ver[i]==fr) continue;
count(ver[i],x,dep+1);
dist[x]+=dist[ver[i]];
}
return ;
}
void dfs(int x,int fr){
ans=max(ans,cnt);
for(int i=head[x];i;i=nxt[i]){
if(ver[i]==fr) continue;
long long c=cnt,dx=dist[x],dy=dist[ver[i]];
cnt-=dist[ver[i]];
dist[x]-=dist[ver[i]];
cnt+=dist[x];
dist[ver[i]]+=dist[x];
dfs(ver[i],x);
cnt=c,dist[x]=dx,dist[ver[i]]=dy;
}
return ;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
for(int i=1;i<n;++i){
int u,v;
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
ans=cnt=0;
count(1,-1,0);
dfs(1,-1);
printf("%lld",ans);
return 0;
}
C.涂抹果酱
- 美妙的三进制状压DP;
- 重载运算符半小时,写过代码十分钟
然而并没有用重载运算符(悲); - 设 \(f_{i,j}\) 表示在第 \(i\) 层为状态 \(j_{_{(三进制压缩后)}}\ \ \ \ \ \ \ \ \
\) 有多少种方法;
预处理出每种合法状态可能转移出哪些状态;
再依次往下一层递推即可; - 另:听隔壁 \(yxr\) 大佬说如果你用假的三进制状压(即直接像字符串一样拼成数字)由于范围比较小也不会爆;
Ac code
#include<iostream>
#include<ios>
#include<cstring>
#include<cmath>
#include<vector>
#include <complex>
using namespace std;
const int mod=1e6;
int n,m,k;
int a[7];
int f[10005][1005];
int g(int y){
int m=3,cnt=1;
for(;y;y>>=1,m*=m)
if(y&1) cnt*=m;
return cnt;
}
int l(int x,int y){
return x*g(y)%mod;
}
int r(int x,int y){
return x/g(y);
}
vector<int>v[1005];
bool use[1005];
void check(){
for(int j=0;j<l(1,m);++j){
int num[7];
use[j]=true;
for(int i=0;i<m;++i){
num[i]=r(j,i)%3;
if(i>0 && num[i]==num[i-1]){
use[j]=false;
break;
}
}
}
return ;
}
void prepare(){
check();
for(int i=0;i<l(1,m);++i){
if(!use[i]) continue;
for(int j=0;j<l(1,m);++j){
if(!use[j]) continue;
bool s=false;
for(int q=0;q<m;++q)
if(r(i,q)%3==r(j,q)%3){
s=true;
break;
}
if(!s) v[i].push_back(j);
}
}
return ;
}
int main(){
scanf("%d%d%d",&n,&m,&k);
int cnt=0;
for(int i=1;i<=m;++i){
scanf("%d",&a[i]);
cnt+=l(a[i]-1,i-1);
}
prepare();
int ans[2];
ans[0]=ans[1]=0;
f[k][cnt]=1;
for(int i=k;i>1;--i)
for(int j=0;j<l(1,m);++j)
if(f[i][j])
for(int q=0;q<v[j].size();++q)
(f[i-1][v[j][q]]+=f[i][j])%=mod;
for(int i=0;i<l(1,m);++i)
(ans[0]+=f[1][i])%=mod;
for(int i=k;i<n;++i)
for(int j=0;j<l(1,m);++j)
if(f[i][j])
for(int q=0;q<v[j].size();++q)
(f[i+1][v[j][q]]+=f[i][j])%=mod;
for(int i=0;i<l(1,m);++i)
(ans[1]+=f[n][i])%=mod;
if(k==1) printf("%d",ans[1]);
else if(k==n) printf("%d",ans[0]);
else printf("%d",(1ll*ans[0]*ans[1])%mod);
return 0;
}

浙公网安备 33010602011771号