文章目录
CF 1946C Tree Cutting
二分
dfs,从下往上看,某个子树满足条件就砍一刀
有个要注意的卡我好久的地方是,最后判断的时候不能加上sz[1] == 0
,因为1为根结点的这个子树很可能是不满足条件的,但是我们底下满足条件的子树已经达到要求了,所以1不满足要求也没关系
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 1e5 + 10;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n, k;
cin >> n >> k;
vector<vector<int>> g(n + 1);
for (int i = 0; i < n - 1; i ++ )
{
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
vector<int> sz(n + 1, 1);
int cnt = 0;
function<void(int, int, int)> dfs1 = [&](int u, int far, int x)
{
sz[u] = 1;
for (int i = 0; i < g[u].size(); i ++ )
{
int j = g[u][i];
if (j == far) continue;
dfs1(j, u, x);
sz[u] += sz[j];
}
if (sz[u] >= x)
{
cnt ++ ;
sz[u] = 0;
}
};
auto check = [&](int x)
{
cnt = 0;
dfs1(1, 0, x);
if (cnt > k && sz[1] == 0) return true;
else return false;
};
int l = 1, r = n;
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
cout << r << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
}
CF 1244C The Football Season
xw + yd = p
可以转换为 (x + d) w + (y - w) d = p
当 y - w >= w
的时候,如果转换把 y - w
转换为 y % w
,那少的一个 wd
可以由前面的 (x + d) w
补齐,所以我们只需要枚举 (y - w)
在区间 [0, w - 1]
的情况即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 1e5 + 10;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n, p, w, d;
cin >> n >> p >> w >> d;
int x = -1, y = -1;
for (int i = 0; i < w; i ++ ) // 枚举 y
{
if ((p - i * d) % w != 0) continue;
int tmpx = (p - i * d) / w;
if (tmpx >= 0 && n - tmpx - i >= 0)
{
x = tmpx, y = i;
cout << x << ' ' << y << ' ' << n - x - y << '\n';
return;
}
}
cout << -1 << '\n';
return;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}
CF 1132F Clear the String
很典的区间dp
如果 s[l] == s[r]
那么 dp[l][r] = dp[l + 1][r - 1] + 1
如果 s[l] != s[r]
那么 dp[l][r] = min(dp[l + 1][r], dp[l][r - 1]) + 1
第三点比较特殊,积累下来:枚举中间点 k ,dp[l][r] = min(dp[l][r], dp[l][k] + dp[k][r] - 1)
为什么不是 dp[l][k] + dp[k + 1][r]
呢?因为有可能 s[l] == s[r] == s[k]
,那lkr三个位置的只需要一次就可以消掉了
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 1e5 + 10;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n;
string s;
cin >> n >> s;
s = " " + s + " ";
vector<vector<int>> dp(n + 2, vector<int>(n + 2));
for (int i = 1; i <= n; i ++ ) dp[i][i] = 1;
for (int len = 2; len <= n; len ++ )
{
for (int l = 1; l + len - 1 <= n; l ++ )
{
int r = l + len - 1;
if (s[l] == s[r]) dp[l][r] = dp[l + 1][r - 1] + 1;
else dp[l][r] = min(dp[l + 1][r], dp[l][r - 1]) + 1;
for (int k = l; k <= r; k ++ )
dp[l][r] = min(dp[l][r], dp[l][k] + dp[k][r] - 1);
}
}
cout << dp[1][n] << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}
CF 540C Ice Cave
第二道自己写的2000!(等自己写出十道就加难度~((不过这貌似也比较水
思路是起点开始跑bfs,除了终点外的X
是不能走的,一般情况下如果终点是X
,那走到就是胜利,除非起点和终点一样(这个情况需要特判一下)
然后看终点上下左右四个方块能不能走到:
- 如果终点是
.
,那至少要能走到两个 - 否则,至少要能走到一个
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 1e5 + 10;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
int dx[] = {0, 0, 1, -1}, dy[] = {1, -1, 0, 0};
void solve()
{
int n, m;
cin >> n >> m;
vector<vector<char>> g(n + 1, vector<char>(m + 1));
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
cin >> g[i][j];
int stx, sty, edx, edy;
cin >> stx >> sty >> edx >> edy;
vector<PII> pos;
if (edx - 1 > 0) pos.push_back({edx - 1, edy});
if (edx + 1 <= n) pos.push_back({edx + 1, edy});
if (edy - 1 > 0) pos.push_back({edx, edy - 1});
if (edy - 1 <= m) pos.push_back({edx, edy + 1});
vector<vector<bool>> st(n + 1, vector<bool>(m + 1));
queue<PII> q;
q.push({stx, sty});
bool flag = false;
while (q.size())
{
auto t = q.front();
q.pop();
int x = t.first, y = t.second;
if (x == edx && y == edy)
{
if (g[x][y] == 'X' && (stx != edx || sty != edy))
{
cout << "YES\n";
return;
}
else flag = true;
}
if (st[x][y]) continue;
st[x][y] = true;
for (int i = 0; i < 4; i ++ )
{
int nx = x + dx[i], ny = y + dy[i];
if (nx <= 0 || nx > n || ny <= 0 || ny > m) continue;
if (st[nx][ny] || (g[nx][ny] == 'X' && (nx != edx || ny != edy))) continue;
q.push({nx, ny});
}
}
if (!flag) cout << "NO" << '\n';
else
{
int cnt = 0;
for (auto t : pos)
{
if (st[t.first][t.second]) cnt ++ ;
}
if (g[edx][edy] == '.')
{
if (cnt >= 2) cout << "YES\n";
else cout << "NO\n";
}
else
{
if (cnt >= 1) cout << "YES\n";
else cout << "NO\n";
}
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}
CF 1200E Compress Words
KMP
对每一个输入的字符串求 ne 数组,然后用前面已经处理过的字符串求相同的前后缀
还有个字符串哈希的做法明天看 现在要去跑步了捏
不要再用 substr
了!!! 直接遍历比它要快!!!
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 1e5 + 10;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n;
cin >> n;
string s, t;
cin >> s;
int sl = s.size();
s = " " + s;
for (int k = 1; k < n; k ++ )
{
sl = s.size() - 1;
cin >> t;
int tl = t.size();
t = " " + t;
vector<int> ne(tl + 1);
for (int i = 2; i <= tl; i ++ )
{
int j = ne[i - 1];
while (j && t[i] != t[j + 1]) j = ne[j];
if (t[i] == t[j + 1]) j ++ ;
ne[i] = j;
}
int j = 0;
for (int i = max((int)(sl - tl + 1), (int)1); i <= sl; i ++ )
{
while (j && s[i] != t[j + 1]) j = ne[j];
if (s[i] == t[j + 1]) j ++ ;
}
for (j = j + 1; j <= tl; j ++ ) s.push_back(t[j]);
}
for (int i = 1; i < s.size(); i ++ ) cout << s[i];
cout << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}