前缀和

1)求和

https://www.luogu.com.cn/discuss?forum=P8772

2)统计子矩阵

https://www.luogu.com.cn/problem/P8783

前缀和,四层循环tle2
#include <iostream>
using namespace std;

const int MAXN = 510;
int a[MAXN][MAXN];
int s[MAXN][MAXN];  // 前缀和矩阵

int main() {
    int n, m, k;
    cin >> n >> m >> k;

    // 输入矩阵元素
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            cin >> a[i][j];
            // 计算前缀和矩阵
            s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
        }
    }

    int count = 0;
    // 枚举左上角坐标 (x1, y1)
    for (int x1 = 1; x1 <= n; x1++) {
        for (int y1 = 1; y1 <= m; y1++) {
            // 枚举右下角坐标 (x2, y2)
            for (int x2 = x1; x2 <= n; x2++) {
                for (int y2 = y1; y2 <= m; y2++) {
                    // 利用前缀和矩阵计算子矩阵的和
                    int sum = s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1];
                    // 判断子矩阵的和是否不超过 K
                    if (sum <= k) {
                        count++;
                    }
                    else {
                        break;
                    }
                }
            }
        }
    }

    cout << count << endl;
    return 0;
}
正解
#include<bits/stdc++.h>
using namespace std;
long long n, m, k, a[510][510], sum[510][510], b[510];
long long l, r, now, ans;
int main() {
	cin >> n >> m >> k;
	for (int i = 1;i <= n;i++)
		for (int j = 1;j <= m;j++)
			cin >> a[i][j];
	for (int j = 1;j <= m;j++)
		for (int i = 1;i <= n;i++)
			sum[i][j] = sum[i - 1][j] + a[i][j];
	//处理竖着的和 第j列前i个数的和
	for (int x = 1;x <= n;x++)
		for (int y = x;y <= n;y++) {
			//	cout<<x<<" "<<y<<":"<<endl;
			//横线x y
			for (int j = 1;j <= m;j++)
				b[j] = sum[y][j] - sum[x - 1][j];
			//双指针  这里已经简化到普通的子串和小于k了
			l = 1;r = 1;now = 0;
			for (r = 1;r <= m;r++) {
				now += b[r];
				if (now <= k) {
					//每次r++新增一个数,这个数可以和前面组成r-l+1,以这个新增的数结尾的子数组
					//	cout<<l<<" "<<r<<" "<<now<<endl; 
					ans += r - l + 1;
				}
				else {
					while (now > k) {
						now -= b[l];
						l++;
					}
					ans += r - l + 1;
				}
			}
			//	cout<<"-------"<<endl;
		}
	cout << ans << endl;
	return 0;
}

3)子串简写数量统计

https://www.lanqiao.cn/problems/3514/learning/

忘记初始化字符串以后的,之后应该初始化为最大的,并且如果数据范围不够大会导致某些测试点,这里开5e5+10会错,6e5+10可以

错误代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 5e5 + 10;
int st1[maxn], st2[maxn];
int k;
string s;
char c1, c2;
int ans;
signed main()
{
    cin >> k;
    cin >> s;
        cin >> c1 >> c2;
    for (int i = 0;i < s.size();i++)
    {
       /* st1[i] = st1[i - 1];
        if (s[i] == c1)
            st1[i]++;*/

        st2[i] = st2[i - 1];
        if (s[i] == c2)
            st2[i]++;
    }
    for (int i = 0;i < s.size();i++)
    {
        if (s[i] == c1)
        {
            ans += st2[s.size()-1] - st2[i + k-2];
        }
    }
    cout << ans << endl;


}
前缀和
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 6e5 + 10;
int st1[maxn], st2[maxn];
int k;
string s;
char c1, c2;
int ans;
signed main()
{
    cin >> k;
    cin >> s;
    cin >> c1 >> c2;
    for (int i = 0;i < s.size();i++)
    {
        /* st1[i] = st1[i - 1];
         if (s[i] == c1)
             st1[i]++;*/

        st2[i] = st2[i - 1];
        if (s[i] == c2)
            st2[i]++;
    }
    for (int i = s.size();i < maxn;i++) st2[i] = st2[s.size() - 1];
    for (int i = 0;i < s.size();i++)
    {
        if (s[i] == c1)
        {
            ans += st2[s.size() - 1] - st2[i + k - 2];
        }
    }
    cout << ans << endl;


}
posted on 2025-03-10 22:15  Hoshino1  阅读(29)  评论(0)    收藏  举报