http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1065
我的思路比较笨,我是直接二分那个答案mid
然后进行一次O(nlogn)的判定,如果能找到一个区间的和比mid小的,(当然这个区间的和也是要大于0),那就return true
进行判断如下:
处理出前缀和dp[i],对于每一个i
目标是:在前i - 1个中,查看是否有这样的一个x,使得,dp[i] - x <= mid,&& dp[i] - x >= 1
二分找x,把前i - 1个东西压去set中,然后二分找x >= dp[i] - mid的那个x,判定即可。
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <assert.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> #include <bitset> const int maxn = 50000 + 20; LL dp[maxn]; int n; set<LL>ss; bool check(LL val) { if (dp[1] <= val && dp[1] >= 1) return true; ss.clear(); ss.insert(0); ss.insert(dp[1]); LL mx = max(0LL, dp[1]); for (int i = 2; i <= n; ++i) { LL x = dp[i] - val; if (mx < x) { mx = max(mx, dp[i]); ss.insert(dp[i]); continue; } set<LL> :: iterator it = ss.lower_bound(x); if (dp[i] - *it >= 1) return true; mx = max(mx, dp[i]); ss.insert(dp[i]); } return false; } void work() { scanf("%d", &n); for (int i = 1; i <= n; ++i) { int x; scanf("%d", &x); dp[i] = dp[i - 1] + x; } // for (int i = 1; i <= n; ++i) { // cout << dp[i] << " "; // } // cout << endl; LL be = 1, en = 1e18L; // cout << check(1) << endl; while (be <= en) { LL mid = (be + en) >> 1; if (check(mid)) { en = mid - 1; } else be = mid + 1; } // cout << be << endl; printf("%lld\n", be); } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif work(); return 0; }
时间: 2024-10-09 20:18:36