洛谷题单 【算法2-1】前缀和与差分

P1115 最大子段和

思路

参考了题解代码~
(虽然这题放在差分这里但是我用差分法会过不去时间,就参考了题解里的dp)
f [ i ] f[i] f[i]为从i开始向前连续延申的最大子段和,最终的最大子段和就是 f [ i ] f[i] f[i]中最大的
洛谷题单 【算法2-1】前缀和与差分_第1张图片

实现

#include
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<

其他

来自洛谷题解区

洛谷题单 【算法2-1】前缀和与差分_第2张图片

P3397 地毯

思路

差分法的入门练习题,先差分,再求和

实现

#include 
#include 
#define rep(i,j,k) for(int i=j;i>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<

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,如果precur,就给[cur,pre-1]这个区间里的铁路都加1。
  • 用差分来实现给一个区间里的所有数都加1。这道题是先差分insert,再累加,最后比较买票和办卡哪个花费少。

实现

#include 
#include 
#include 
#define rep(i,j,k) for(int i=j;i>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<

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 
#include 

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 
#include 
#include 
#define rep(i,j,k) for(int i=j;i>n>>m>>c;
    vector > a(n+1,vector(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<

P5638 【CSGRound2】光骓者的荣耀

思路

既然可以跳到第 i + k i+k i+k或第 i − k i-k ik个城市,那么要走的路尽可能少,一定是跳到 i + k i+k i+k个城市,并且这个 i i i满足:第 i i i个城市和第 i + k i+k i+k个城市之间的距离最长。题意其实就是,找出在一个数组中长度为k的连续子序列的和的最大值。一维前缀和,累加的同时找最大值即可。

实现

#include 
#include 
#include 
#include 
using namespace std;

typedef long long ll;


int main()
{
	int n,k;
	ll max_ = 0;
	ll sum = 0;
	cin>>n>>k;
	vector a(n);
	a[0] = 0;
	for(int i=1;i

P2671 [NOIP2015 普及组] 求和

思路

待补充-

实现

#include 
#include 
#include 
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;
}

欢迎指正-

你可能感兴趣的:(洛谷,算法,c++)