【简●解】[USACO] 照片Photo

【题目大意】#

1~N的序列上有M个区间,使得这M个小区间每个覆盖了且仅覆盖了一个点,求最多点数,如果无解,输出1

【分析】#

刚开始做的时候我是懵的。。。不管三七二十一开始想差分约束系统,无奈没那么好的思维,没想出来。。。
一翻题解,,WOC这是什么神仙DP?真的是学到了。。。

我们设f[i]表示序列的第i位是一个点时,序列1~i的最多点数。

那么dp方程就很好推了:设j<i,即有f[i]=max(f[j]+1,f[i])

现在我们需要解决的是j的范围,也就是f[i]能从哪些状态中转移过来。

我们想,如果第i位是一个点,那么所有包含这个点的区间都不能再有点,也就是说,j必须小于包含第i位这个点的区间中最小的左端点
同样的,每个区间上必须有一个点,所以,j必须大于或等于不包含第i位这个点的区间中最大的左端点

至于怎么求,大家可以YY了。

我们会惊奇地发现DP方程满足单调性,于是单调队列走起。

细节见代码。

至于差分约束的做法嘛,,,以后会补的,,,咕咕咕

【code】#

Copy
//#include<bits/stdc++.h> #pragma GCC optimize("O3") #pragma GCC optimize("O2") #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; const int MAX = 2000000 + 5; inline int read(){ int f = 1, x = 0;char ch; do { ch = getchar(); if (ch == '-') f = -1; } while (ch < '0'||ch>'9'); do {x = x*10+ch-'0'; ch = getchar(); } while (ch >= '0' && ch <= '9'); return f*x; } int n, m, l[MAX], r[MAX], f[MAX], ans, q[MAX]; int main(){ // freopen("aaa.in", "r", stdin); // freopen("aaa.out", "w", stdout); int n = read(), m = read(); for (int i = 1;i <= n + 1; ++i) r[i] = i - 1; for (int i = 1;i <= m; ++i) { int x = read(), y = read(); r[y] = min(r[y], x - 1); l[y + 1] = max(l[y + 1], x); } for (int i = n; i > 0; --i) r[i] = min(r[i], r[i + 1]); for (int i = 2; i < n + 2; ++i) l[i] = max(l[i], l[i - 1]); int j = 1, h = 1, t = 1; q[1] = 0; for (int i = 1;i <= n + 1; ++i) { while (j <= r[i] && j <= n) { if (f[j] == -1) { ++j; continue; } while (f[j] > f[q[t]] && h <= t) --t; q[++t] = j; ++j; } while (q[h] < l[i] && h <= t) ++h; if (h <= t) f[i] = f[q[h]] + (i != n+1 ? 1 : 0); else f[i] = -1; } printf("%d", f[n + 1]); return 0; }
posted @   SilentEAG  阅读(349)  评论(2编辑  收藏  举报
编辑推荐:
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示
CONTENTS