diff --git a/TangDou/Topic/PrefixAndSuffix/P1115_DP.cpp b/TangDou/Topic/PrefixAndSuffix/P1115_DP.cpp new file mode 100644 index 0000000..7c206f7 --- /dev/null +++ b/TangDou/Topic/PrefixAndSuffix/P1115_DP.cpp @@ -0,0 +1,17 @@ +#include +using namespace std; +const int N = 200100; +int ans = INT_MIN; +int n; +int a[N], dp[N]; + +int main() { + cin >> n; + for (int i = 1; i <= n; i++) { + cin >> a[i]; + dp[i] = max(dp[i - 1] + a[i], a[i]); + ans = max(ans, dp[i]); + } + printf("%d\n", ans); + return 0; +} \ No newline at end of file diff --git a/TangDou/Topic/PrefixAndSuffix/P1115.cpp b/TangDou/Topic/PrefixAndSuffix/P1115_Prefix.cpp similarity index 90% rename from TangDou/Topic/PrefixAndSuffix/P1115.cpp rename to TangDou/Topic/PrefixAndSuffix/P1115_Prefix.cpp index 2805f03..68ef708 100644 --- a/TangDou/Topic/PrefixAndSuffix/P1115.cpp +++ b/TangDou/Topic/PrefixAndSuffix/P1115_Prefix.cpp @@ -1,6 +1,6 @@ #include using namespace std; -const int N = 1e6 + 10; +const int N = 200100; const int INF = 0x3f3f3f3f; int n, a[N], s[N], ans[N]; diff --git a/TangDou/Topic/【前缀和与差分】题单.md b/TangDou/Topic/【前缀和与差分】题单.md index 65c2a35..76f2fa2 100644 --- a/TangDou/Topic/【前缀和与差分】题单.md +++ b/TangDou/Topic/【前缀和与差分】题单.md @@ -22,6 +22,7 @@ **分析** 先求每个位置的前缀和(某个区间求和前缀和可以说是最快的),然后去找该位置前前缀和的最小值,如果要求一段和最大,就要用这段和减去前面最小的值。 +**前缀和解法** ```cpp {.line-numbers} #include using namespace std; @@ -46,6 +47,27 @@ int main() { } ``` +$DP$ 解法 +```cpp {.line-numbers} +#include +using namespace std; +const int N = 200100; +int ans = INT_MIN; +int n; +int a[N], dp[N]; + +int main() { + cin >> n; + for (int i = 1; i <= n; i++) { + cin >> a[i]; + dp[i] = max(dp[i - 1] + a[i], a[i]); + ans = max(ans, dp[i]); + } + printf("%d\n", ans); + return 0; +} +``` + #### [$P1083$ [$NOIP2012$ 提高组] 借教室](https://www.luogu.com.cn/problem/P1083) #### 暴力 @@ -308,37 +330,35 @@ int main() { } ``` -**$O(N^3)$算法** -这道题和$P1115$最大子段和思路类似。 -只是将一维升到二维,很重要的解决思路:**矩阵压缩**。 -如果能把二维降到一维,那就好处理了。 - -假设有一个矩阵: -```cpp {.line-numbers} --5 6 4 -1 -2 6 -2 1 -3 -``` -想得到其中任意一个矩阵,我们不妨先确定列。 -很明显用两个循环嵌套可以解决。 -假设我们取$2,3$列 -```cpp {.line-numbers} -6 4 --1 6 -1 -3 -``` +**$O(N^3)$算法**【选读】 +> **引子**: +> 给出一段序列,选出其中连续且非空的一段使得这段和最大。第一行是一个正整数$N$,表示了序列的长度。($N<=200000$) +> +这是 $P1115$最大子段和 的描述,也就是本题的一维版本。 -列取好之后那么每一行的和值就是确定的了。 +$DP$方程:`dp[i]=max(dp[i-1]+a[i],a[i])` $a[i]$ 表示这个数列的第$i$项。 -**注意**:用前缀和可以优化时间。 ```cpp {.line-numbers} -10 -5 --2 +#include +using namespace std; +const int N = 200100; +int ans = INT_MIN; +int n; +int a[N] , dp[N]; + +int main(){ + cin>>n; + for(int i=1;i<=n;i++){ + cin>>a[i]; + dp[i]=max(dp[i-1]+a[i],a[i]); + ans=max(ans,dp[i]); + } + printf("%d\n",ans); + return 0; +} ``` -接下来我们再在这个一维数组中求最大子序列的和。 -就和$P1115$的做法一样了! + **$Code$**