提高组复赛训练

DAY2
A
在这里插入图片描述
在一个长这样的的一个网格图,每次给你一个起点和终点,并且只能往下以及往右走,问所经过点权和的不同的数量

有一个显然的结论:
不同的数量为(走最大 - 走最小 + 1)
然后可以发现恰好就为 ( n − 1 ) ∗ ( m − 1 ) + 1 (n - 1) * (m - 1) + 1 (n1)(m1)+1
其中 n , m n,m nm为给定矩形的长宽

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;

ll T,a,b,c,d;

int main(){
	cin>>T;
	while(T--){
		scanf("%lld%lld%lld%lld" , &a , &b , &c , &d);
		printf("%lld\n" , (c - a) * (d - b) + 1ll);
	}
	
}

B:
有一个长度为 n n n且只包含小写字母的字符串S。

你需要执行一些操作来清除S。

每一次操作,你可以选择S的任意子串,满足该子串由同一个字符组成,然后清除这一子串。

至少需要多少次操作才能清空字符串S?
F [ l ] [ r ] F[l][r] F[l][r]为清空 S [ l ] − − − S [ r ] S[l] ---S[r] S[l]S[r]的最小操作数目
转移如下
F [ l ] [ r ] = F [ l + 1 ] [ r ] ( S [ l ] = = S [ l + 1 ] ) F [ l ] [ r ] = F [ l ] [ r − 1 ] ( S [ r ] = = S [ r − 1 ] ) F [ l ] [ r ] = m i n ( F [ l + 1 ] [ r ] , F [ l ] [ r − 1 ] ) [ S [ l ] = = S [ r ] ] F [ l ] [ r ] = m i n ( F [ l ] [ k ] , F [ k + 1 ] [ r ] ) F[l][r] = F[l + 1][r] (S[l] == S[l + 1]) \\ F[l][r] = F[l][r - 1] (S[r] == S[r - 1]) \\ F[l][r] = min(F[l + 1][r] , F[l][r - 1])[S[l] == S[r]] \\ F[l][r] = min(F[l][k] , F[k + 1][r]) F[l][r]=F[l+1][r](S[l]==S[l+1])F[l][r]=F[l][r1](S[r]==S[r1])F[l][r]=min(F[l+1][r],F[l][r1])[S[l]==S[r]]F[l][r]=min(F[l][k],F[k+1][r])

#include<bits/stdc++.h>
#define MAXN 505
using namespace std;

int n,f[MAXN][MAXN],ans = 0x3f3f3f3f;
char a[MAXN];

/*
f[l][r][35]

*/

int main(){
	cin>>n;
	scanf("%s" , a + 1);
	memset(f , 0x3f , sizeof(f));
	for(int i = 1 ; i <= n ; i++)f[i][i] = 1;
	for(int len = 2 ; len <= n ; len++){
		for(int i = 1 ; i + len - 1 <= n ; i++){
			int j = i + len - 1;
			for(int k = i ; k < j ; k++)
			f[i][j] = min(f[i][j] , f[i][k] + f[k + 1][j]);
			if(a[i] == a[i + 1])f[i][j] = min(f[i][j] , f[i + 1][j]);
			if(a[j] == a[j - 1])f[i][j] = min(f[i][j] , f[i][j - 1]);
			if(a[i] == a[j])f[i][j] = min(f[i][j] , min(f[i + 1][j] , f[i][j - 1]));
		}
	}
	ans = f[1][n];
	for(int i = 1 ; i < n ; i++)ans = min(ans , f[1][i] + f[i + 1][n]);
	cout<<ans<<endl;
}

C
你将得到根为1,包含 n n n个结点的一棵树。

假设这颗树有 k k k个叶子结点,你需要给这kk个叶子结点加上一个不同的值,大小为1到k1到k,(1到k1到k每个数字出现一次)。

其次,这棵树的每个结点有一个操作属性,属性为0,表示当前结点值为所有孩子结点的最小值,属性为1,表示当前结点值为所有孩子结点的最大值。(叶子结点上的操作忽略)

在所有填充方式中,根结点的最大值是多少?

正解是暴力
每个节点的情况可以归纳成
每个孩子 最多能有第 A [ i ] A[i] A[i]
1:如果当前节点取min
那么 当前节点最多为 s i g a m a ( A [ i ] − 1 ) + 1 sigama(A[i] - 1) + 1 sigama(A[i]1)+1
2:如果当前节点取max
那么 当前节点最多为 a l l − s z [ i ] + A [ i ] all - sz[i] + A[i] allsz[i]+A[i]

#include<bits/stdc++.h>
#define MAXN 400005
using namespace std;

int n,h[MAXN],tot,num[MAXN],f[MAXN],ans[MAXN],sum;

struct node{int from,to,next;}e[MAXN << 1];

void add(int x , int y){
	tot++;
	e[tot].from = x;
	e[tot].to = y;
	e[tot].next = h[x];
	h[x] = tot;
}

void dfs(int now , int fa){
	if(h[now] == (-1))sum++;
	for(int i = h[now] ; i != (-1) ; i = e[i].next){
		dfs(e[i].to , now);
	}
	if(num[now] == 1){
		int ok = 0;
		for(int i = h[now] ; i != (-1) ; i = e[i].next){
			if(!ok)ok = 1 , ans[now] = ans[e[i].to];
			else ans[now] = min(ans[now] , ans[e[i].to]);
		}
	}
	if(num[now] == 0){
		for(int i = h[now] ; i != (-1) ; i = e[i].next){
			ans[now] = ans[now] + max(1 , ans[e[i].to]);
		}
	}
}

int main(){
	memset(h , -1 , sizeof(h));tot = 0;
	cin>>n;
	for(int i = 1 ; i <= n ; i++)cin>>num[i];
	int x;
	for(int i = 2 ; i <= n ; i++){
		cin>>x;
		add(x , i);
		f[i] = x;
	}
	dfs(1 , 1);
	if(ans[1])cout<<sum - ans[1] + 1<<endl;
	else cout<<sum<<endl;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值