Color with Occurrences
题意
思路
首先想到
D
P
DP
DP的做法,我们构造
d
p
(
i
)
dp(i)
dp(i)表示位置
i
i
i上能够涂满红色的最小方案数,对于位置
i
i
i,我们遍历
m
m
m个匹配串,如果能成功匹配,就更新当前位置上的
d
p
dp
dp值加一,并向前维护最小值。
运算出所有位置的dp值后,我们不断回溯
d
p
dp
dp值减一所匹配的位置去匹配最长的可匹配子串并输出下标和位置即可
状态转移方程:
d
p
[
i
]
=
(
d
p
[
i
−
l
e
n
]
+
1
,
d
p
[
i
]
)
dp[i] = (dp[i - len] + 1, dp[i])
dp[i]=(dp[i−len]+1,dp[i])
代码
void run () {
cin >> P + 1 >> m;
n = strlen(P + 1);
rep (i, 1, m) cin >> s[i];
mem(f, 0x3f);
f[0] = 0;
rep (i, 1, n) {
rep (j, 1, m) {
int len = SZ(s[j]);
if(i >= len) {
string tmp = "";
rep (k, i - len + 1, i) tmp += P[k];
if (tmp == s[j]) {
f[i] = min(f[i], f[i - len] + 1);
rep (k, 1, i - 1) f[k] = min(f[i], f[k]);
}
}
}
}
if (f[n] == INF) TO(-1);
else {
int idx = f[n];
cout << idx << endl;
while (idx) {
bool isOK = 0;
for (int i = n; i >= 1 && !isOK; i -- ) {
if (f[i] == idx && !isOK) {
set<string> st;
for (int j = 1; j <= m && !isOK; j ++ ) {
int len = SZ(s[j]);
string tmp = "";
rep (k, i - len + 1, i) tmp += P[k];
if (tmp == s[j]) st.insert(tmp);
}
int len = -1;
for (auto it : st) len = max(len, SZ(it));
for (int j = 1; j <= m && !isOK; j ++ ) {
if (st.count(s[j]) && SZ(s[j]) == len) {
cout << j << ' ' << i - len + 1 << endl;
idx --;
isOK = 1;
}
}
}
}
}
}
}
题意
思路
本题我们只要预处理出每个前缀的b[i],之后对根节点到a[i]进行二分即可得到答案
代码
void dfs(int u, int p) {
for (int i = h[u]; ~i ; i = ne[i]) {
int j = e[i];
if(j != p) {
s[j] = s[u] + a[i];
if(!v.size()) v.pb(b[i]);
else { int t = v.back(); v.pb(t + b[i]); }
res[j] = upper_bound(v.begin(), v.end(), s[j]) - v.begin() ;
dfs(j, u);
v.pop_back();
}
}
}
void run() {
cin >> n;
rep (i, 2, n) {
int u, x, y; cin >> u >> x >> y;
add(u, x, y);
}
dfs(1, 0);
rep (i, 2, n) cout << res[i] << " ";
cout << endl;
}