P1115 最大子段和
思路
参考了题解代码~
(虽然这题放在差分这里但是我用差分法会过不去时间,就参考了题解里的dp)
令
f
[
i
]
f[i]
f[i]为从i开始向前连续延申的最大子段和,最终的最大子段和就是
f
[
i
]
f[i]
f[i]中最大的
实现
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a[200010],p,ans[200010]={0};
int sum=-9999999;
cin>>p;
for(int i=1;i<=p;i++)
{
cin>>a[i];
ans[i]=max(ans[i-1]+a[i],a[i]);//DP
sum=max(sum,ans[i]);
}
cout<<sum;
return 0;
}
其他
来自洛谷题解区
P3397 地毯
思路
差分法的入门练习题,先差分,再求和
实现
#include <iostream>
#include <vector>
#define rep(i,j,k) for(int i=j;i<k;i++)
using namespace std;
int b[1010][1010];
void insert(int x1, int y1, int x2, int y2, int c)
{
b[x1][y1] += c;
b[x2 + 1][y1] -= c;
b[x1][y2 + 1] -= c;
b[x2 + 1][y2 + 1] += c;
}
int main()
{
int n; //列数
int m;
cin>>n>>m;
int x1,x2,y1,y2;
rep(i,0,m)
{
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
insert(x1,y1,x2,y2,1);
}
rep(i,1,n+1)
{
rep(j,1,n+1)
{
b[i][j] += b[i-1][j]+b[i][j-1]-b[i-1][j-1];
printf("%d ",b[i][j]);
}
cout<<endl;
}
return 0;
}
P3406 海底高铁
思路
- 对于同一段铁路,我们要么一直买票,要么一直办卡。假设这条铁路一共走了n次,关键就是比较 n A nA nA和 C + n B C+nB C+nB哪个小。
- 首先需要统计出每一小段路程需要走多少次,比如城市3–>城市1,就需要给第1、2段铁路加1,比如1–>4,就需要给1、2、3段加1。规律就是读入两个数分别命名为pre和cur,如果pre<cur,就给[pre,cur-1]这个区间里的铁路都加1,如果pre>cur,就给[cur,pre-1]这个区间里的铁路都加1。
- 用差分来实现给一个区间里的所有数都加1。这道题是先差分insert,再累加,最后比较买票和办卡哪个花费少。
实现
#include <iostream>
#include <vector>
#include <algorithm>
#define rep(i,j,k) for(int i=j;i<k;i++)
using namespace std;
long long b[101000];
void insert(int l, int r, int c)
{
b[l] += c;
b[r + 1] -= c;
}
int main()
{
int n,m;
cin>>n>>m;
int pre,cur;
scanf("%d",&pre);
rep(i,1,m)
{
scanf("%d",&cur);
if(cur>pre)
insert(pre,cur-1,1);
else
insert(cur,pre-1,1);
pre = cur;
}
long long ans = 0;
rep(i,1,n)
{
b[i]+=b[i-1];
// cout<<b[i];
ans+=b[i];
}
//cout<<ans;
ans = 0;
int a,bb,c;
rep(i,1,n)
{
scanf("%d %d %d",&a,&bb,&c);
ans+= min(a*b[i],bb*b[i]+c);
}
cout<<ans;
return 0;
}
P1719 最大加权矩形
思路
前缀和的方法就是四层循环
优化的方法有:先压缩再一维dp (来自洛谷题解
对于矩形
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
先在竖直方向算出前缀和
0 -2 -7 0
9 0 -13 2
5 1 -17 3
4 9 -17 1
之后,i和j是选择的两行,i从0到n-1,j从i+1到n。每次先选择两行,然后
d
p
[
k
]
dp[k]
dp[k]表示在这两行之间到第k列为止的向前连续的最大子矩阵。(可以先做一下P1115最大子段和理解向前连续)
实现
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 330;
int n, a[N][N], res = -9999999, dp[N];
int main(){
cin >> n;
//前缀和(竖直方向)
for (int i = 1 ; i <= n ; i ++ ){
for (int j = 1 ; j <= n ; j ++ ){
cin >> a[i][j];
a[i][j] += a[i - 1][j];
}
}
//降维变成一维dp
for (int i = 0 ; i <= n - 1 ; i ++ ){
for (int j = i + 1 ; j <= n ; j ++ ){
for (int k = 1 ; k <= n ; k ++ ){
dp[k] = max(a[j][k] - a[i][k], dp[k - 1] + a[j][k] - a[i][k]);
res = max(res, dp[k]);
}
}
}
cout << res;
return 0;
}
P2004 领地选择
思路
二维前缀和的模板题,需要注意边界
实现
#include <iostream>
#include <algorithm>
#include <vector>
#define rep(i,j,k) for(int i=j;i<k;i++)
using namespace std;
typedef long long ll;
int main(){
int n,m,c;
cin>>n>>m>>c;
vector<vector<ll> > a(n+1,vector<ll>(m+1,0));
rep(i,1,n+1)
{
rep(j,1,m+1)
{
scanf("%lld",&a[i][j]);
a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
// cout<<a[i][j]<<" ";
}
// cout<<endl;
}
ll ans = a[1][1];
ll area;
int max_i,max_j;
rep(i,1,n-c+2)
{
rep(j,1,m-c+2)
{
area = a[i+c-1][j+c-1]+a[i-1][j-1]-a[i-1][j+c-1]-a[i+c-1][j-1];
if(ans<area)
{ans = area;
max_i = i;
max_j = j;
}
}
}
cout<<max_i<<" "<<max_j;
return 0;
}
P5638 【CSGRound2】光骓者的荣耀
思路
既然可以跳到第 i + k i+k i+k或第 i − k i-k i−k个城市,那么要走的路尽可能少,一定是跳到 i + k i+k i+k个城市,并且这个 i i i满足:第 i i i个城市和第 i + k i+k i+k个城市之间的距离最长。题意其实就是,找出在一个数组中长度为k的连续子序列的和的最大值。一维前缀和,累加的同时找最大值即可。
实现
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
int main()
{
int n,k;
ll max_ = 0;
ll sum = 0;
cin>>n>>k;
vector<ll> a(n);
a[0] = 0;
for(int i=1;i<n;i++)
{
scanf("%d",&a[i]);
a[i]+=a[i-1];
//cout<<a[i]<<endl;
}
for(int i=k;i<=n;i++)
{
max_ = max(max_,a[i]-a[i-k]);
}
cout<<a[n-1]-max_;
return 0;
}
P2671 [NOIP2015 普及组] 求和
思路
待补充-
实现
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 100010, MOD = 10007;
int num[N], color[N];
LL s[N][2], cnt[N][2];
int n, m;
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> num[i];
for (int i = 1; i <= n; i++)
{
cin >> color[i];
s[color[i]][i % 2] = (s[color[i]][i % 2] + num[i]) % MOD;
cnt[color[i]][i % 2]++;
}
LL res = 0;
for (int i = 1; i <= n; i++)
res = (res + i * ((cnt[color[i]][i % 2] - 2) * num[i] + s[color[i]][i % 2])) % MOD;
cout << res << endl;
return 0;
}
欢迎指正-