Codeforces 1084C
题意:给定一个$n$长小写字母序列,找出只包含a
的子序列,满足每两个a
之间有b
,求方案数。
DP思想。从后往前扫,对每个a
维护从这个位置开始顺序,这个位置必选的合法序列数量。
对于更新,不妨用b
将序列分块,每个a
只能继承他右边最近的一块的值。然后自身还有一个贡献,累加即可。
Codeforces 1084D
题意:树上每个点有正权值$a_i$,每条边有负权值$W$,你可以随意选择一条路径,使得这条路径的总权值最大,要求每个点每条边至多都只能走一次。
一开始想得好偏……
然而就是个树形DP,设$dp(u)$为$u$子树中的某个点到$u$的路径最长权。则转移为
$dp(u)=max(dp(v)-W(u,v)+a_u)$,当且仅当$dp(v)-W(u,v) \leq 0$
然后这样最后要统计每个点的$dp$值取个$max$就行了
等等,路径不一定是”直”的。所以我们要在DP每个点的过程中合并两条路径来得到”弯”的路径
这里弯直的意思是可能存在下面的情况:
1
|
2
|
3
直:1-2-3
1
|
/ \
2 3
弯:2-1-3
知识点:
1、计数问题逃不了DP、组合数学
2、树上最优问题要像到DP,路径不要漏了弯的路径
1093C:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<bitset>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
#define db double
#define fir first
#define sec second
#define mp make_pair
using namespace std;
namespace flyinthesky {
const LL MAXN = 100000 + 5, MO = 1e9 + 7;
LL n;
char s[MAXN];
void clean() {
}
int solve() {
clean();
scanf("%s", s + 1ll);
n = strlen(s + 1ll);
LL ans = 0ll, tot = 0ll, lsttot = 0ll;
for (LL i = n; i; --i) {
if (s[i] == 'a') ans = (ans + lsttot + 1ll) % MO, tot = (tot + lsttot + 1ll) % MO;
else if (s[i] == 'b' && tot) lsttot = (lsttot + tot) % MO, tot = 0ll;
}
cout << ans;
return 0;
}
}
int main() {
flyinthesky::solve();
return 0;
}
1093D:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<bitset>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
#define db double
#define fir first
#define sec second
#define mp make_pair
using namespace std;
namespace flyinthesky {
const LL MAXN = 300000 + 5;
LL ans, n, dp[MAXN], dw[MAXN];
vector<LL > G[MAXN], W[MAXN];
void ins(LL u, LL v, LL w) {G[u].push_back(v), W[u].push_back(w);}
void dfs(LL u, LL fa) {
dp[u] = dw[u];
LL maxd = 0, cid = 0;
for (LL i = 0; i < (LL)G[u].size(); ++i) {
LL v = G[u][i], bw = W[u][i];
if (v != fa) {
dfs(v, u);
if (dp[v] - bw >= 0ll) {
dp[u] = max(dp[u], dp[v] - bw + dw[u]);
if (dp[v] - bw > maxd) {
cid = maxd, maxd = dp[v] - bw;
} else if (dp[v] - bw > cid) {
cid = dp[v] - bw;
}
}
}
}
ans = max(ans, dw[u] + cid + maxd);// 合并两条路径
}
void clean() {
ans = 0ll;
}
int solve() {
clean();
scanf("%lld", &n);
for (LL i = 1; i <= n; ++i) scanf("%lld", &dw[i]);
for (LL u, v, w, i = 1; i < n; ++i) {
scanf("%lld%lld%lld", &u, &v, &w);
ins(u, v, w), ins(v, u, w);
}
dfs(1, 0);
for (LL i = 1; i <= n; ++i) ans = max(ans, dp[i]);
cout << ans;
return 0;
}
}
int main() {
flyinthesky::solve();
return 0;
}