c/c++语言开发共享洛谷P4563 [JXOI2018]守卫(dp)

题意 “题目链接” Sol 非常有意思的题目。 我们设$f[l][r]$表示区间$[l,r]$的答案。 显然$r$位置一定有一个保镖 同时不难观察到一个性质:拿$[1, n]$来说,设其观察不到的某个区间为$[l_k, r_k]$,那么$r_k$与$r_k + 1$一定有一个保镖,而且每段区间的贡献 …


题意

题目链接

sol

非常有意思的题目。

我们设(f[l][r])表示区间([l,r])的答案。

显然(r)位置一定有一个保镖

同时不难观察到一个性质:拿([1, n])来说,设其观察不到的某个区间为([l_k, r_k]),那么(r_k)(r_k + 1)一定有一个保镖,而且每段区间的贡献都是独立的。

这样我们可以预处理出任意两个点是否能看见(直接记上一个能看到的位置然后比较斜率)。

然后直接枚举(r),不断把(l)往左移动更新答案,这样可以保证更新的时候中间的区间都计算过,可以直接前缀和优化

复杂度(o(n^2))

#include<bits/stdc++.h> #define fin(x) freopen(#x".in", "r", stdin); using namespace std; const int maxn = 5001; template<typename a, typename b> inline bool chmax(a &x, b y) {return x < y ? x = y, 1 : 0;} template<typename a, typename b> inline bool chmin(a &x, b y) {return x > y ? x = y, 1 : 0;} inline int read() {     char c = getchar(); int x = 0, f = 1;     while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();     return x * f; } int n, f[maxn][maxn]; double a[maxn]; bool can[maxn][maxn]; int main() {     //fin(a);     n = read();     for(int i = 1; i <= n; i++) a[i] = read();     for(int i = 1; i <= n; i++) {         for(int j = i - 1, las = -1; j; j--)              if((las == -1) || (1ll * (a[i] - a[las]) * (i - j) > 1ll * (a[i] - a[j]) * (i - las)))                  can[i][j] = can[j][i] =1, las = j;     }     int ans= 0;     for(int i = 1; i <= n; i++) {         int s = 1, las = 0;         for(int j = i; j; j--) {             if(can[j][i]) {                 if(!can[j + 1][i]) s += min(f[j + 1][las], f[j + 1][las + 1]);                 f[j][i] = s;             } else {                 if(can[j + 1][i]) las = j;                 f[j][i] = s + min(f[j][las], f[j][las + 1]);             }             ans ^= f[j][i];         //  printf("%d ", f[j][i]);         }     //  puts("");     }     cout << ans;     return 0; }

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/c-cdevelopment/605037.html

(0)
上一篇 2021年5月13日
下一篇 2021年5月13日

精彩推荐