DAY2
A
在一个长这样的的一个网格图,每次给你一个起点和终点,并且只能往下以及往右走,问所经过点权和的不同的数量
有一个显然的结论:
不同的数量为(走最大 - 走最小 + 1)
然后可以发现恰好就为
(
n
−
1
)
∗
(
m
−
1
)
+
1
(n - 1) * (m - 1) + 1
(n−1)∗(m−1)+1
其中
n
,
m
n,m
n,m为给定矩形的长宽
#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][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])
#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]
all−sz[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;
}