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;
}
posted @ 2022-03-21 17:21  Star_LIcsAy  阅读(33)  评论(0)    收藏  举报