8.9

P13557
AT_abc416_f [ABC416F] Paint Tree 2

P13557

赛时转成曼哈顿距离后人傻了

image

发现如果鱼在红色箭头处,朝箭头所指方向游动,那么只要把网布在蓝色区域就可以捉到(蓝色区域可向上,下,右无限延伸)

也就是只要做二维差分就可以了,但是注意数据范围,发现横纵坐互不影响,分别离散化后计算, 取两个前缀和数组中的最大值相加

#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
const int maxn=1e5+5;
const int inf=1e5+1;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=x*10+c-48;
	x=(f ? -x : x);
	return;
}
void read(char& c){
	do{
		c=getchar();
	}while(c==10||c==13);
}
int x[maxn],y[maxn];
int xt[maxn],yt[maxn];
char d[maxn];
int n;
vector<int> v;
void ls(int* a){
	v.resize(0);
	for(int i=1;i<=n;i++){
		v.push_back(a[i]);
	}
	sort(v.begin(),v.end());
	v.erase(unique(v.begin(),v.end()),v.end());
	for(int i=1;i<=n;i++){
		a[i]=lower_bound(v.begin(),v.end(),a[i])-v.begin()+1;
	}
}
int main(){
	int t;
	read(t);
	while(t--){
		read(n);
		for(int i=1;i<=n;i++){
			read(x[i]),read(y[i]),read(d[i]);
		}
		ls(x),ls(y);
		memset(xt,0,sizeof(xt)),memset(yt,0,sizeof(yt));
		for(int i=1;i<=n;i++){
			if(d[i]=='L') ++xt[1],--xt[x[i]+1];
			else if(d[i]=='R') ++xt[x[i]];
			else if(d[i]=='D') ++yt[1],--yt[y[i]+1];
			else ++yt[y[i]];
		}
		int ansx=0,ansy=0;
		for(int i=1;i<=inf;i++){
			xt[i]+=xt[i-1],yt[i]+=yt[i-1];
			ansx=max(ansx,xt[i]),ansy=max(ansy,yt[i]);
		}
		printf("%d\n",ansx+ansy);
	}
	return 0;
}
//^o^

50%完成,今晚要打abc了

AT_abc416_f [ABC416F] Paint Tree 2

8.10补

k很小,想到树上dp

设计状态dp[maxn][6][3]

第一维:当前的点

第二维:已经选取的路径数

第三维:当前的点,0不在链上,1在一条链上的端点,2在链上却不是端点

枚举当前选取的边数以及该子节点所占得边数

以下转移中mx=max({dp[v][j][0],dp[v][j][1],dp[v][j][2]})

j为0,则mx=dp[v][j][0]

五种转移:

一,2状态可以由1状态再加上当前子节点的1状态合并而来,前提是当前节点的1状态不能只选0条路径
if(j) dp[u][i][2]=max(dp[u][i][2],dp[u][i-j+1][1]+dp[v][j][1]);

二,2状态可以由2状态再加上当前子节点的任意状态,前提是当前节点的2状态不能只选0条路径
if(i-j) dp[u][i][2]=max(dp[u][i][2],dp[u][i-j][2]+mx);

三,1状态可以由1状态再加上当前子节点的任意状态,前提是当前节点的1状态不能只选0条路径
if(i-j) dp[u][i][1]=max(dp[u][i][1],dp[u][i-j][1]+mx);

四,1状态可以由当前子节点的1状态向上加上该端点得来,前提是当前子节点的1状态不能只选0条路径
dp[u][i][0]=max(dp[u][i][0],dp[u][i-j][0]+mx);

五,0状态可以由0状态再加上当前子节点的任意状态,没有前提
dp[u][i][0]=max(dp[u][i][0],dp[u][i-j][0]+mx);

#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
const int maxn=2e5+5;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=x*10+c-48;
	x=(f ? -x : x);
	return;
}
void read(char& c){
	do{
		c=getchar();
	}while(c==10||c==13);
}
int head[maxn],nxt[maxn<<1],e[maxn<<1];
int mp_cnt;
void init_mp(){
	memset(head,-1,sizeof(head));
	mp_cnt=-1;
}
void add_edge(int u,int v){
	e[++mp_cnt]=v;
	nxt[mp_cnt]=head[u];
	head[u]=mp_cnt;
}
int n,k;
LL dp[maxn][6][3];
int a[maxn];
void dfs(int u,int fa){
	dp[u][1][1]=a[u];
	for(int i=head[u];~i;i=nxt[i]){
		int v=e[i];
		if(v==fa) continue;
		dfs(v,u);
		for(int i=k;i>=0;i--){
			for(int j=0;j<=i;j++){
				LL mx=max({dp[v][j][0],dp[v][j][1],dp[v][j][2]});
				if(!j) mx=dp[v][j][0];
				if(j) dp[u][i][2]=max(dp[u][i][2],dp[u][i-j+1][1]+dp[v][j][1]);
				if(i-j) dp[u][i][2]=max(dp[u][i][2],dp[u][i-j][2]+mx);
				if(i-j) dp[u][i][1]=max(dp[u][i][1],dp[u][i-j][1]+mx);
				if(j) dp[u][i][1]=max(dp[u][i][1],dp[u][i-j][0]+dp[v][j][1]+a[u]);
				dp[u][i][0]=max(dp[u][i][0],dp[u][i-j][0]+mx);
			}
		}
	}
}
int main(){
	read(n),read(k);
	for(int i=1;i<=n;i++){
		read(a[i]);
	}
	int u,v;
	init_mp();
	for(int i=1;i<n;i++){
		read(u),read(v);
		add_edge(u,v),add_edge(v,u);
	}
	dfs(1,1);
	LL ans=0;
	for(int i=0;i<=k;i++){
		ans=max(ans,max({dp[1][i][0],dp[1][i][1],dp[1][i][2]}));
	}
	printf("%lld",ans);
	return 0;
}
//^o^
posted @ 2025-08-09 19:32  huangems  阅读(15)  评论(0)    收藏  举报