CF1313D Happy New Year
CF1313D Happy New Year
思路
一道不错的思维题。入手点在于观察到
先离散化诅咒涉及到的所有点,接着记
枚举该点所有状态,接着标记的转移可以
具体转移如下:
我们需要给当前点
-
若
是起点- 若
,意味着 是新加入的编号,要从 处没有这个编号的状态更新过来。 有奇数个标记产生新贡献。
- 若
,意味着 是已加入的编号,直接从 继承过来即可。 有奇数个标记产生新贡献。
- 若
-
若
是终点- 若
,这是不合法的。 - 若
,意味着编号 之前可能有,也可能没有,要两种情况取较大。 有奇数个标记产生新贡献。
- 若
你或许有这样的疑惑:为什么是从
因此我们采用给诅咒赋编号的方法,值得一提的是不同点同一编号的诅咒完全可能不是同一个诅咒。所谓的
时间复杂度
#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l); i <= (r); ++ i)
#define G(i,r,l) for(int i(r); i >= (l); -- i)
using namespace std;
using ll = long long;
const int N = 2e5 + 5;
const int inf = 0x3f3f3f3f;
vector<pair<int, int> > a;
int f[300], vis[18];
int n, m, kt;
signed main(){
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> n >> m >> kt;
F(i, 1, n){
int L, R;
cin >> L >> R;
a.push_back({L, i});
a.push_back({R + 1, -i});
} int cnt = a.size();
sort(a.begin(), a.end());
F(i, 1, 255) f[i] = -inf;
F(i, 0, cnt - 1){
int id = a[i].second, k;
int len = (i == cnt - 1) ? 0 : (a[i + 1].first - a[i].first);
if(id > 0){
F(i, 0, 7){
if(vis[i] == 0){
k = i;
vis[k] = id;
break;
}
}//distribute an id
G(i, 255, 0){
if((i >> k) & 1){
f[i] = f[i ^ (1 << k)] + len * __builtin_parity(i);
// da xiao
}
else{
f[i] = f[i] + len * __builtin_parity(i);
}
}
}
else{
F(i, 0, 7){
if(vis[i] == -id){
k = i;
vis[k] = 0;
break;
}
}
F(i, 0, 255){
if((i >> k) & 1){
f[i] = -inf;
}
else{
f[i] = max(f[i], f[i ^ (1 << k)]) + len * __builtin_parity(i);
//xiao da
}
}
}
}
cout << f[0] << '\n';
return fflush(0), 0;
}
总结
本题关键是要想通只关注每个点上诅咒数量就可以,不需要关心具体的诅咒。其他题解中提到了扫描线这一思想,个人感觉不是重点。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】