- 这周为了学可持久化平衡树,又去学了下fhq-treap,好用啊
- 学了左偏树但没学懂k短路
- 看了cup-pyy佬的训练方式,再结合一下学长的训练建议,想了又想还是刷abc,不刷题根本不知道什么算法用的多,刷了之后自然就分清什么useful什么useless了,光学数据结构的话,看到题目根本都想不到是这个数据结构啊,根据之前的训练经验来看,板刷对我自己而言是比较有效的训练方式,新算法也要学但不能把大部分时间放在上面了
- 周末去打了省赛,拿到了除了女生赛之外的第一块铜牌,但是打得也确实糟糕,卡题卡得想丝,应该要出四题的,另外也有决策上的失误,m有思路之后应该立刻和队友说让他们开下一题不要再管m的,但是当时还是特别不自信,想着如果这样做了但最后自己没能做出m那就真要背锅了,另外最后一小时应该开的题可能是e而不是j,e据说就是爆搜(?),但是j这种图论一个小时真的不好调(怎么和图论杠上了啊,杭州站也是最后一小时卡图论来着)
CF 1221D Make The Fence Great Again (二维dp)
看完题目的第一个思路是二分,但是实在想不出check函数怎么写
第二个思路是bfs更新每个点的状态,利用优先队列先处理b小的位置,但后来发现也不对
于是看题解发现是可恶的dp
dp[i][j]
表示到第 i 个位置为止,且第 i 个位置增加了 j 次的最小消耗,但是这不是n方吗!注意,每个点最多增加两次,再加多了也是浪费,所以 j 的取值 0 / 1 / 2 即可
#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 = 2e5 + 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;
vector<int> a(n + 2), b(n + 2);
for (int i = 1; i <= n; i ++ ) cin >> a[i] >> b[i];
vector<vector<int>> dp(n + 2, vector<int>(3, INF));
dp[1][0] = 0, dp[1][1] = b[1], dp[1][2] = 2 * b[1];
for (int i = 2; i <= n; i ++ )
{
for (int j = 0; j < 3; j ++ )
{
for (int k = 0; k < 3; k ++ )
{
if (a[i] + j != a[i - 1] + k) dp[i][j] = min(dp[i - 1][k] + j * b[i], dp[i][j]);
}
}
}
cout << min({dp[n][0], dp[n][1], dp[n][2]}) << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
}
CF 1442A Extreme Subtraction (差分+思维)
很妙的差分,如果想到差分的话应该就很容易
想让所有数变成0,那么就是让差分数组全部为0以及让数列的第一项为0
第一个操作的结果是:suf[1] --; suf[k + 1] ++;
也就是让数列第一项减一,差分数组第k+1项加1
第二个操作的结果是:suf[n + 1] ++; suf[n - k + 1] --;
也就是让差分数组第n-k+1项减1
说得更清楚一点,第一个操作可以减少数组首项的值,同时把差分数组中小于0的数加1,第二个操作可以把差分数组中大于0的数减1(且不会造成其他任何影响,也就是第二个操作可以随意进行,所以我们不用管差分数组中大于0的数)
所以只要看差分数组中的负数的绝对值之和是否超过数组第一项即可
#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 = 2e5 + 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;
vector<int> a(n);
for (int i = 0; i < n; i ++ ) cin >> a[i];
int tmp = 0;
for (int i = 0; i < n; i ++ )
{
if (i > 0 && a[i] - a[i - 1] < 0) tmp -= a[i] - a[i - 1];
}
if (tmp <= a[0]) 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 1500A Going Home (观察数据)
这题的困难之处就是看数据不能n方枚举,但是又不能不枚举,所以观察数据,发现a最大是2.5e6,说明之后相加的和不会超过5e6,枚举这个复杂度是可以接受的,所以就还是枚举,最坏情况下枚举5e6次是一定能找到一样的
#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 = 5e6 + 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;
vector<int> a(n + 1);
vector<int> mp1(N), mp2(N);
for (int i = 1; i <= n; i ++ ) cin >> a[i];
for (int i = 1; i <= n; i ++ )
{
for (int j = i + 1; j <= n; j ++ )
{
int sum = a[i] + a[j];
if (mp1[sum] != i && mp1[sum] != j && mp2[sum] != i && mp2[sum] != j && mp1[sum] != 0 && mp2[sum] != 0)
{
cout << "YES\n";
cout << i << ' ' << j << ' ' << mp1[sum] << ' ' << mp2[sum] << '\n';
return;
}
else mp1[sum] = i, mp2[sum] = j;
}
}
cout << "NO\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}