2026-02-09~02-12 hetao1733837 的刷题记录
02-09
LGP4447 [AHOI2018初中组] 分组
原题链接:[AHOI2018初中组] 分组
分析
啊?这咋二分?转变一下维度思考一下......看一下别人的代码......今天我一定要跑步!
?很......二分在哪?
正解
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
map<int, int> buc;
priority_queue<int, vector<int>, greater<int>> q[N];
int n, a[N], tp;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++){
cin >> a[i];
}
sort(a + 1, a + n + 1);
for (int i = 1; i <= n; i++){
if (buc[a[i]] == 0){
buc[a[i]] = ++tp;
}
if (buc[a[i] - 1] == 0 || q[buc[a[i] - 1]].empty()){
q[buc[a[i]]].push(1);
}
else{
int tmp = q[buc[a[i] - 1]].top() + 1;
q[buc[a[i] - 1]].pop();
q[buc[a[i]]].push(tmp);
}
}
int ans = 0x3f3f3f3f;
for (int i = 1; i <= n; i++){
if (!q[buc[a[i]]].empty()){
ans = min(ans, q[buc[a[i]]].top());
}
}
cout << ans;
return 0;
}
02-10
CF868F Yet Another Minimization Problem
原题链接1:CF868F Yet Another Minimization Problem
原题链接2:F. Yet Another Minimization Problem
分析
这个真的是凸的吗?分治和 DP 的结合......
还是有点太困难了。那么,从暴力转移入手,设 d p i , j dp_{i,j} dpi,j 表示考虑到了位置 i i i,分成了 j j j 段的最小花费,转移显然。
然后各种分治优化......并未看懂吧......
hyw?
正解
cpp
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 100005, K = 25;
const long long INF = 1e18;
int n, k, a[N];
int cnt[N];
long long dp[N][K];
int l, r, p;
long long sum = 0;
long long calc(int s, int t){
while (l > s){
l--;
sum += cnt[a[l]];
cnt[a[l]]++;
}
while (r < t){
r++;
sum += cnt[a[r]];
cnt[a[r]]++;
}
while (l < s){
cnt[a[l]]--;
sum -= cnt[a[l]];
l++;
}
while (r > t){
cnt[a[r]]--;
sum -= cnt[a[r]];
r--;
}
return sum;
}
void solve(int L, int R, int ml, int mr){
int mid = (L + R) >> 1;
long long mn = INF;
int tl = max(1LL, ml), tr = min(mid, mr);
int pos = tl;
for (int i = tl; i <= tr; i++){
long long tmp = dp[i - 1][p - 1] + calc(i, mid);
if (tmp < mn){
mn = tmp;
pos = i;
}
}
dp[mid][p] = mn;
if (L == R)
return;
solve(L, mid, ml, pos);
solve(mid + 1, R, pos, mr);
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> k;
for (int i = 1; i <= n; i++){
cin >> a[i];
}
for (int i = 0; i <= n; i++){
for (int j = 0; j <= k; j++){
dp[i][j] = INF;
}
}
dp[0][0] = 0;
p = 1;
while (p <= k){
l = 1, r = 0;
sum = 0;
memset(cnt, 0, sizeof(cnt));
solve(1, n, 1, n);
p++;
}
cout << dp[n][k];
return 0;
}
还是太困难了/ll
02-11
LGP3803 【模板】多项式乘法(FFT)
原题链接:【模板】多项式乘法(FFT)
分析
和 DeepSeek 聊了很久,感觉好了一些吧......其实没看懂这个讲的是啥,但是还是决定整一下板子......
正解
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 4000005;
const double PI = acos(-1.0);
struct node{
double x, y;
node (double tx = 0, double ty = 0){
x = tx;
y = ty;
}
}a[N], b[N];
node operator+(node tx, node ty){
return node(tx.x + ty.x, tx.y + ty.y);
}
node operator-(node tx, node ty){
return node(tx.x - ty.x, tx.y - ty.y);
}
node operator*(node tx, node ty){
return node(tx.x * ty.x - tx.y * ty.y, tx.x * ty.y + tx.y * ty.x);
}
void FFT(int lim, node *k, int tp){
if (lim == 1)
return ;
node t1[lim >> 1], t2[lim >> 1];
for (int i = 0; i < lim; i += 2){
t1[i >> 1] = k[i];
t2[i >> 1] = k[i + 1];
}
FFT(lim >> 1, t1, tp);
FFT(lim >> 1, t2, tp);
node wn = node(cos(2.0 * PI / lim), tp * sin(2.0 * PI / lim));
node w = node(1, 0);
for (int i = 0; i < (lim >> 1); i++, w = w * wn){
k[i] = t1[i] + w * t2[i];
k[i + (lim >> 1)] = t1[i] - w * t2[i];
}
}
int n, m;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for (int i = 0; i <= n; i++){
cin >> a[i].x;
a[i].y = 0;
}
for (int i = 0; i <= m; i++){
cin >> b[i].x;
b[i].y = 0;
}
int lim = 1;
while (lim <= n + m){
lim <<= 1;
}
FFT(lim, a, 1);
FFT(lim, b, 1);
for (int i = 0; i < lim; i++){
a[i] = a[i] * b[i];
}
FFT(lim, a, -1);
for (int i = 0; i <= n + m; i++){
cout << (int)(a[i].x / lim + 0.5) << " ";
}
}
02-12
LGP7831 [CCO 2021] Travelling Merchant
原题链接:[CCO 2021] Travelling Merchant
分析
似乎,对于每一个点,我找到图上一个最小环就结了?咦,这不是个贪吗?哦,就每次在所有出边里走?这么简单?套一个类似拓扑的东西,就没了......
正解
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
int n, m, d[N], ans[N];
struct node{
int a, b, r, p;
}inp[N];
bool cmp(node x, node y){
return x.r < y.r;
}
vector<int> e[N];
queue<int> q;
bool vis[N];
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= m; i++){
cin >> inp[i].a >> inp[i].b >> inp[i].r >> inp[i].p;
d[inp[i].a]++;
}
sort(inp + 1, inp + m + 1, cmp);
for (int i = 1; i <= m; i++){
e[inp[i].b].push_back(i);
}
for (int i = 1; i <= n; i++){
if (!d[i]){
q.push(i);
}
}
memset(ans, 0x3f, sizeof(ans));
for (int i = m; i >= 1; i--){
while (!q.empty()){
int u = q.front();
q.pop();
for (auto v : e[u]){
if (vis[v])
continue;
vis[v] = 1;
d[inp[v].a]--;
if (!d[inp[v].a]){
q.push(inp[v].a);
}
if (ans[u] != 0x3f3f3f3f){
ans[inp[v].a] = min(ans[inp[v].a], max(inp[v].r, ans[u] - inp[v].p));
}
}
}
if (!vis[i]){
vis[i] = 1;
d[inp[i].a]--;
if (!d[inp[i].a])
q.push(inp[i].a);
ans[inp[i].a] = min(ans[inp[i].a], inp[i].r);
}
}
for (int i = 1; i <= n; i++){
if (ans[i] != 0x3f3f3f3f){
cout << ans[i] << " ";
}
else{
cout << -1 << " ";
}
}
}
[AGC009C] Division into Two
原题链接1:[AGC009C] Division into Two
原题链接2:C - Division into Two
分析
上了个厕所......依旧感谢一下 DeepSeek !思考怎么做......不考虑时间的话......咦,我们可不可以这样设 DP ,就是设 d p i , j dp_{i,j} dpi,j 表示(这个在离散化意义下似乎比较好说明) A 的最大元素为 s i s_i si,B 为 s j s_j sj,的序列划分数那么,转移即为......
其实我也不知道......但是,我们似乎可以再次嵌套一个二分......思考一下......好的,优化一维,因为是个划分,所以不属于 A 则必定属于 B ,那么留下一维,然后另一维同样二分出来,找到某个区间可以转移,即同时满足 A 和 B 的限制,直接拿下......细节方面......思考一下......然后拿一个前缀和......甚至不用二分,由于单调性,甚至掏一个指针就能过!
正解
cpp
#include <bits/stdc++.h>
#define int long long
#define mod 1000000007
using namespace std;
const int N = 100005;
int n, A, B, s[N], dp[N];
int sum[N];
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> A >> B;
if (A < B)
swap(A, B);
for (int i=1;i<=n;i++){
cin>>s[i];
}
for(int i=3;i<=n;i++){
if(s[i]-s[i-2]<B){
cout << 0 << '\n';
return 0;
}
}
dp[0] = sum[0] = 1;
int l = 0, r = 0;
for (int i = 1; i <= n; i++){
while (r < i && s[i] - s[r + 1] >= A)
r++;
if (l <= r)
dp[i] = sum[r] - (l == 0 ? 0ll : sum[l - 1]);
dp[i] = (dp[i] % mod + mod) % mod;
sum[i] = (sum[i - 1] + dp[i]) % mod;
if (i > 1 && s[i] - s[i - 1] < B)
l = i - 1;
}
int ans = 0;
for (int i = n; ~i; i--){
ans = (ans + dp[i]) % mod;
if (i < n && s[i + 1] - s[i] < B)
break;
}
cout << ans << '\n';
}
不管了,我要回去学 BO !
反思一下......我应该没有做错什么,或许不完美......我要回生竞那边了。