首页 > 其他分享 >4 前缀和与差分 参考代码

4 前缀和与差分 参考代码

时间:2023-07-28 17:03:40浏览次数:42  
标签:const 前缀 int 代码 d% 差分 MAXN include scanf

P8218 [深进1.例1] 求区间和

数列 \(\{a_n\}\) 的前缀和为 \(S_n = \sum_{i=1}^{n} a_i = a_1 + a_2 + \cdots + a_n\)
则区间 \([l,r]\) 的区间和为 \(a_l + a_{l+1} + \cdots + a_r = S_r - S_{l - 1}\)
预处理出前缀和,则单次区间和的查询就做到了 \(O(1)\) 复杂度

#include <cstdio>
const int MAXN = 100005;
int a[MAXN], sum[MAXN];
int main()
{
	int n, m;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
		sum[i] = sum[i - 1] + a[i];
	}
	scanf("%d", &m);
	while (m--) {
		int l, r;
		scanf("%d%d", &l, &r);
		printf("%d\n", sum[r] - sum[l - 1]);
	}
	return 0;
}

P5638 [CSG Round 2] 光骓者的荣耀

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 1000005;
LL a[MAXN], sum[MAXN];
int main()
{
    int n, k;
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n - 1; i++) {
        scanf("%lld", &a[i]);
        sum[i] = sum[i - 1] + a[i];
    }
    if (k == 0) {
        printf("%lld\n", sum[n - 1]);
    }
    LL ans = sum[n - 1];
    for (int i = 1; i <= n - k; i++) {
        LL cur = sum[n - 1] - (sum[i + k - 1] - sum[i - 1]);
        ans = min(ans, cur);
    }
    printf("%lld\n", ans);
    return 0;
}

P1115 最大子段和

#include <cstdio>
const int MAXN = 200005;
const int INF = 2e9;
int a[MAXN];
int main()
{
	int n;
	scanf("%d", &n);
	int sum = 0, ans = -INF, pre = 0;
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
		sum += a[i];
		// sum 为以i位置结尾的前缀和
		// pre 为i位置之前的最小前缀和
		// 则sum-pre为以i位置为结尾的最大子段和
		if (sum - pre > ans) ans = sum - pre;	
		if (sum < pre) pre = sum;
	}
	printf("%d\n", ans);
	return 0;
}
  • 注意到结果可能是个负数,因此记录最大子段和的变量初始值应设成一个很小的负数

P1719 最大加权矩形

先求出每一列的前缀和,固定要选的矩形的上下边界,此时将每一列的总和压成一个数,则问题被转化为最大子段和问题

#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 125;
int a[MAXN][MAXN], sumc[MAXN][MAXN];
int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++) {
            scanf("%d", &a[i][j]);
            sumc[i][j] = sumc[i - 1][j] + a[i][j];
        }
    int ans = -2e6;
    for (int i = 1; i <= n; i++) { // 枚举上边界
        for (int j = i; j <= n; j++) { // 枚举下边界
			// 计算最大子段和
            int maxsum = 0;
            int cur = 0;
            for (int k = 1; k <= n; k++) {
                if (cur < 0) cur = 0;
				// 将第i行到第j行在k这一列的和压成一个数
                cur += sumc[j][k] - sumc[i - 1][k]; 
                maxsum = max(maxsum, cur);
            }
            ans = max(ans, maxsum);
        }
    }
    printf("%d\n", ans);
    return 0;
}
  • 结果可能是个负数,记录结果的变量初始值应设成一个很小的负数

P3131 [USACO16JAN] Subsequences Summing to Sevens S

#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 50005;
int a[MAXN];
int f[7]; // f数组记录1~6这七种前缀和(对7取余)第一次出现的位置
// 原理:如果i位置的前缀和(对7取余)等于j位置的前缀和(对7取余),说明i+1到j这一段区间加起来是7的倍数
// 特殊地:当前缀和本身就是7的倍数时,说明整个区间加起来是7的倍数
int main()
{
    int n;
    scanf("%d", &n);
    int sum = 0, ans = 0;
    for (int i = 1; i <= n; i++) {
        int x;
        scanf("%d", &x);
        sum = (sum + x) % 7;
        if (sum == 0) ans = i;
        else if (f[sum] != 0) ans = max(ans, i - f[sum]);
        if (f[sum] == 0) f[sum] = i;
    }
    printf("%d\n", ans);
    return 0;
}

P3397 地毯

#include <cstdio>
const int MAXN = 1005;
int d[MAXN][MAXN], a[MAXN][MAXN];
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 0; i < m; i++) {
        int x1, y1, x2, y2;
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        d[x1][y1]++;
        d[x1][y2 + 1]--;
        d[x2 + 1][y1]--;
        d[x2 + 1][y2 + 1]++;
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            a[i][j] = a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1] + d[i][j];
            printf("%d ", a[i][j]);
        }
        printf("\n");
    }
    return 0;
}

P2367 语文成绩

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 5000005;
const int INF = 2e9;
int a[MAXN], d[MAXN];
int main()
{
	int n, p;
	scanf("%d%d", &n, &p);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
		d[i] = a[i] - a[i - 1];
	}
	while (p--) {
		int x, y, z;
		scanf("%d%d%d", &x, &y, &z);
		d[x] += z; d[y + 1] -= z;
	}
	int ans = INF;
	for (int i = 1; i <= n; i++) {
		d[i] += d[i - 1]; // 对差分数组求前缀和还原出原数组
		ans = min(ans, d[i]);
	}
	printf("%d\n", ans);
	return 0;
}

P2004 领地选择

#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 1005;
int sum[MAXN][MAXN];
int main()
{
    int n, m, c;
    scanf("%d%d%d", &n, &m, &c);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) {
            int x;
            scanf("%d", &x);
            sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + x;
        }
    int ans = sum[c][c];
    int ansi = 1, ansj = 1;
    for (int i = 1; i <= n - c + 1; i++)
        for (int j = 1; j <= m - c + 1; j++) {
            int x = i + c - 1;
            int y = j + c - 1;
            int cur = sum[x][y] - sum[i - 1][y] - sum[x][j - 1] + sum[i - 1][j - 1];
            if (cur > ans) {
                ans = cur;
                ansi = i;
                ansj = j;
            }
        }       
    printf("%d %d\n", ansi, ansj);
    return 0;
}

P2280 [HNOI2003] 激光炸弹

#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 5005;
int a[MAXN][MAXN];
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; ++i) {
        int x, y, v;
        scanf("%d%d%d", &x, &y, &v);
        a[x + 1][y + 1] = v;
    }
    for (int i = 1; i <= 5001; ++i)
        for (int j = 1; j <= 5001; ++j) {
            a[i][j] += a[i][j - 1] + a[i - 1][j] - a[i - 1][j - 1];
        }
    int ans = 0;
    for (int i = m; i <= 5001; ++i)
        for (int j = m; j <= 5001; ++j) {
            ans = max(ans, a[i][j] - a[i - m][j] - a[i][j - m] + a[i - m][j - m]);
        }
    printf("%d\n", ans);
    return 0;
}
  • 注意题目中的 n 是目标的数量,坐标本身的取值范围是 0~5000,可以对其 +1 将值域平移到 1~5001

P3406 海底高铁

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 100005;
LL d[MAXN];
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    int pre = 0;
    for (int i = 1; i <= m; i++) {
        int p;
        scanf("%d", &p);
        if (i > 1) {
            d[min(p, pre)]++;
            d[max(p, pre)]--;
        } 
        pre = p;
    }
    LL sum = 0, ans = 0;
    for (int i = 1; i <= n - 1; i++) {
        LL a, b, c;
        scanf("%lld%lld%lld", &a, &b, &c);
        sum += d[i];
        ans += min(b * sum + c, a * sum);
    }
    printf("%lld\n", ans);
    return 0;
}

P6067 [USACO05JAN] Moo Volume S

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 100005;
LL a[MAXN];
int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
    sort(a + 1, a + n + 1);
    LL ans = 0;
    LL sum = 0;
    for (int i = 1; i <= n; i++) {
        ans += a[i] * (i - 1) - sum;
        sum += a[i];
    }
    printf("%lld\n", ans * 2);
    return 0;
}
  • 这里的前缀和需要 long long 类型才够存下
  • 注意 \((i-1)*a_i\) 的计算结果需要保证是 long long 类型

标签:const,前缀,int,代码,d%,差分,MAXN,include,scanf
From: https://www.cnblogs.com/ronchen/p/17588099.html

相关文章

  • 如何在VSCode中配置GitHub GPT代码辅助提示工具
    安装GitHubGPT插件(如果有的话):在VSCode扩展市场中搜索并安装GitHubGPT插件。该插件可能还不存在,如果是这样,你可能需要开发自定义的代码提示插件。在此假设有一个现有的插件可用。安装VSCode:如果你还没有VSCode,首先要安装它。你可以从VSCode的官方网站(http://www.duozitu.com......
  • 写一段python爬虫下载登录用户商品图片的代码
    要下载登录用户的商品图片,你需要模拟登录网站并获取登录后的会话。下面是一个示例代码,用于登录网站并下载登录用户的商品图片:importrequestsimportosfrombs4importBeautifulSoupdeflogin(username,password):login_url="https://example.com/login"sessio......
  • zabbixn 源码中 ui / frontends 文件夹下的代码文件负责的是哪方面的职责
    ui/frontends代码的职责通过下载源码查看,可以看到在zabbix-4.X中前端代码在frontends目录下,zabbix-6.X在ui目录下,虽然换了个马甲,但里面都是一些php文件。在Zabbix源码中,ui/frontends文件夹下的代码文件负责处理与用户界面(UI)相关的职责。这些文件包含了Zabbix前端......
  • 3.2 排序 参考代码
    P1059[NOIP2006普及组]明明的随机数计数排序#include<cstdio>inta[1005];intmain(){ intn,cnt=0; scanf("%d",&n); for(inti=1;i<=n;i++){ intx;scanf("%d",&x); if(a[x]==0){//这个数没出现过(第一次出现) a[x]=......
  • 代码随想录算法训练营第四十天| 300.最长递增子序列 674. 最长连续递增序列 718.
    300.最长递增子序列要求:可以删减任意个节点,最后保存最大的递增长度难点:410489如何保证全局的视角,看到很前面的节点是否大于当前的节点,而不是仅仅记录状态思路:dp[n],当子序列的末尾为N时,它的最大子序列长度也就意味着,N在它的子序列中是最大的,遍历这个N之前的所有序......
  • 要动手写代码
    0.要培养自学摸索能力1.学习要做笔记让自己更知道自己哪些能理解,哪些不能理解。在自己复习的时候有的放矢学习做笔记也是思考。2.多动手写代码,多练习,多看多练多记录。看得懂完全不等于自己会写。编程是一种技能。你要写代码写得好,除了理解知识点之外,要动手手写。就像卖油翁一......
  • 红帽限制 RHEL 代码访问,瞄准 Rocky Linux 和 AlmaLinux
    导读CentOS Stream是由RedHat公司推出的一个开源操作系统,它与RedHatEnterprise Linux(RHEL)密切相关。事实上,CentOSStream是RHEL开发过程中的一个中间流程(在发布新的RHEL版本之前,RedHat会在CentOSStream开发平台中开发RHEL的源代码),是RHEL的预览版本,包含......
  • python教程 入门学习笔记 第2天 第一个python程序 代码规范 用默认的IDLE (Python GUI
    四、第一个python程序1、用默认的IDLE(PythonGUI)编辑器编写2、在新建文件中写代码,在初始窗口中编译运行3、写完后保存为以.py扩展名的文件4、按F5键执行,在初始窗口观看运行结果5、代码规范:1)先保存再执行2)一句代码单独占一行3)语法中的符号,必须使用英文4)代码前面不能有......
  • 【d2l】【困难代码】【1】 9.7 损失函数
    问题描述神の代码秀我一脸,来搞懂一下问题解决1.torch.tensor的bool索引作用:只保留为true或为1位置处的元素参考:https://deepinout.com/pytorch/pytorch-questions/117_pytorch_can_i_slice_tensors_with_logical_indexing_or_lists_of_indices.html2.torch.tensor中None......
  • 代码随想录算法训练营第二天| LeetCode 977.有序数组的平方 ,209.长度最小的子数组 ,59.
    977.有序数组的平方     题目链接:https://leetcode.cn/problems/squares-of-a-sorted-array/    文章讲解:https://programmercarl.com/0977.%E6%9C%89%E5%BA%8F%E6%95%B0%E7%BB%84%E7%9A%84%E5%B9%B3%E6%96%B9.html    视频讲解: https://www.bili......