【计蒜客 - 蓝桥训练】蒜厂年会(单调队列优化dp,循环数列的最大子段和)
題干:
在蒜廠年會上有一個抽獎,在一個環形的桌子上,有?nn?個紙團,每個紙團上寫一個數字,表示你可以獲得多少蒜幣。但是這個游戲比較坑,里面竟然有負數,表示你要支付多少蒜幣。因為這些數字都是可見的,所以大家都是不會出現的賠的情況。
游戲規則:每人只能抓一次,只能抓取一段連續的紙團,所有紙團上的數字和就是你可以獲得的蒜幣。
蒜頭君作為蒜廠的一員在想,我怎么可以獲得最多的蒜幣呢?最多能獲取多少蒜幣呢?
因為年會是發獎,那么一定有大于?00?的紙團。
輸入格式
第一行輸入一個整數?nn,表示有?nn?個紙團。
第二行輸入輸入?nn?個整數?a_iai?,表示每個紙團上面寫的數字(這些紙團的輸入順序就是環形桌上紙團的擺放順序)。
輸出格式
輸出一個整數,表示蒜頭君最多能獲取多少蒜幣。
數據范圍
對于?30\%30%?的數據:1 \le n \le 10^2,-10^3 \le a_i \le 10^31≤n≤102,?103≤ai?≤103。
對于?60\%60%?的數據:1 \le n \le 5 \times 10^3,-10^6 \le a_i \le 10^61≤n≤5×103,?106≤ai?≤106。
對于?100\%100%?的數據:1 \le n \le 10^5,-10^9 \le a_i \le 10^91≤n≤105,?109≤ai?≤109。
樣例輸入復制
3 1 -2 1樣例輸出復制
2解題報告:
? 單調隊列優化dp。
AC代碼:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int INF = 0x3f3f3f3f; const LL mod = 1e9 + 7; const int N = 200005; int a[N]; LL pre[N]; int main() {int n;scanf("%d", &n);for (int i = 1; i <= n; i++) {scanf("%d", &a[i]);a[n + i] = a[i];}for (int i = 1; i <= 2 * n; i++) {pre[i] = pre[i - 1] + a[i];}deque<int> q;q.push_back(0);LL ans = a[1];for (int i = 1; i <= 2 * n; i++) {if (!q.empty() && q.front() < i - n) {q.pop_front();}ans = max(ans, pre[i] - pre[q.front()]);while (!q.empty() && pre[q.back()] >= pre[i]) {q.pop_back();}q.push_back(i);}printf("%lld\n", ans);return 0; }WA代碼:(只通過60%)
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define ll long long #define pb push_back #define pm make_pair #define fi first #define se second using namespace std; const int MAX = 2e5 + 5; ll a[MAX],dp[MAX],dpp[MAX]; int main() {int n;cin>>n;for(int i = 1; i<=n; i++) cin>>a[i];ll sum = 0 ;for(int i = 1; i<=n; i++) {if(sum >=0) sum += a[i],dp[i] = sum;else sum = a[i],dp[i] = sum;}for(int i = 1; i<=n; i++) {if(sum >=0) sum += a[i],dpp[i] = sum;else sum = a[i],dpp[i] = sum;}cout << max(*max_element(dp+1,dp+n+1),*max_element(dpp+1,dpp+n+1));return 0 ;}最暴力的做法:(肯定會T的)
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int INF = 0x3f3f3f3f; const LL mod = 1e9 + 7; const int N = 200005; int a[N]; LL pre[N]; int main() {int n;scanf("%d", &n);for (int i = 1; i <= n; i++) {scanf("%d", &a[i]);a[n + i] = a[i];}LL ans = a[1];for (int i = 1; i <= n; i++) {LL sum = 0;for (int j = i; j < i + n; j++) {sum += a[j];if (sum > ans) {ans = sum;}}}printf("%lld\n", ans);return 0; }另一個做法:
https://blog.csdn.net/weixin_41544329/article/details/85076111
總結
以上是生活随笔為你收集整理的【计蒜客 - 蓝桥训练】蒜厂年会(单调队列优化dp,循环数列的最大子段和)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【CodeForces - 294B】S
- 下一篇: 假如给你1亿现金,一天后就要归还本金,怎