基础算法
前缀和
一维前缀和
[USACO16JAN] Subsequences Summing to Sevens S - 洛谷
这一题主要是需要结合数学知识来求解,
cpp
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 50010;
int n;
int s[N], l[7], r[7];
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i ++) {
int cur;
scanf("%d", &cur);
// 初始化前缀和矩阵
s[i] = (s[i - 1] + cur) % 7;
}
// 从右往左,记录7的每个余数的最左边的坐标值
for (int i = n; i ; i --) l[s[i]] = i;
// 从左往右,记录7的每个余数的最右边的坐标值
for (int i = 1; i <= n; i ++) r[s[i]] = i;
l[0] = 0;
int res = 0;
for (int i = 0; i <= 6; i ++) {
if (r[i]) res = max(res, r[i] - l[i]);
}
printf("%d\n", res);
return 0;
}
二维前缀和
核心的原理
模板题
活动 - AcWing
例题
这个题的N是100,比较小,可以用三重循环通过;故枚举正方形的边长,记作len
这个题的(x1,y1)等于(i,j) 这个题的(x2,y2)相当于(i+len,j+len)
cpp
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 510;
int a[N][N],s[N][N];
int n,m;
int main()
{
cin>>n>>m;
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 res = 0;
for (int i = 1; i <= n; i ++){
for (int j = 1; j <= m; j ++) {
for (int len = 0; i + len <= n && j + len <= m; len ++) {
if (s[i + len][j + len] - s[i - 1][j + len] - s[i + len][j - 1] + s[i - 1][j - 1] == (len + 1) * (len + 1)){
res = max(len + 1, res);
}
}
}
}
cout<<res<<endl;
return 0;
}
二维前缀和之固定边长的正方形
[HNOI2003] 激光炸弹 - 洛谷
cpp
#include<iostream>
#include<algorithm>
using namespace std;
int n, m;
int s[5050][5050];
int res = 0;
int main()
{
cin >> n >> m;
while (n--)
{
int x, y, v;
cin >> x >> y >> v;
s[x + 1][y + 1] += v;
}
for (int i = 1; i <= 5001; i++)
{
for (int j = 1; j <= 5001; j++)
{
s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
}
}
for (int i = m; i <= 5001; i++)
for (int j = m; j <= 5001; j++)
{
//标准
int value = s[i][j] - s[i - m][j] - s[i][j - m] + s[i - m][j - m];
res = max(res, value);
}
printf("%d", res);
return 0;
}
差分
一维差分
[Poetize6] IncDec Sequence - 洛谷
这个题里面的数学推理我现在都还没看明白
cpp
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
typedef long long ll;
ll a[N];
ll b[N];
ll n;
int main()
{
cin>>n;
for(ll i=1;i<=n;i++)
{
cin>>a[i];
}
ll x,y;
x=y=0;
for(ll i=1;i<n;i++)
{
b[i]=a[i+1]-a[i];
if(b[i]<0)x-=b[i];
else y+=b[i];
}
cout<<max(x,y)<<endl;
cout<<abs(x-y)+1<<endl;
return 0;
}
二维差分
模板题
cpp
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 1e3 + 10;
int a[N][N], b[N][N];
//差分矩阵为什么是这个
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;
}
// 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, m, q;
cin >> n >> m >> q;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin >> a[i][j];
//初始化差分数组
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
insert(i, j, i, j, a[i][j]); //构建差分数组
}
}
while (q--)
{
int x1, y1, x2, y2, c;
cin >> x1 >> y1 >> x2 >> y2 >> c;
insert(x1, y1, x2, y2, c);
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1]; //二维前缀和
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
printf("%d ", b[i][j]);
}
printf("\n");
}
return 0;
}
洛谷地毯 - 洛谷
在模版的基础上稍微变一下形即可
cpp
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 1e3 + 10;
int a[N][N], b[N][N];
//差分矩阵为什么是这个
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;
}
// 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, m, q;
cin >> n >> m;
//初始化差分数组
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
insert(i, j, i, j, 0); //构建差分数组
}
}
while (m--)
{
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
insert(x1, y1, x2, y2, 1);
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1]; //二维前缀和
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
printf("%d ", b[i][j]);
}
printf("\n");
}
return 0;
}
贪心
与排序有关的贪心(注意排序的写法)
结构体排序(记忆一下)
[USACO1.3] 混合牛奶 Mixing Milk - 洛谷
cpp
bool cmp(cow farmer1,cow farmer2)
{
return farmer1.p<farmer2.p;
}
也就是bool cmp(结构体名称 实例1,结构体名称 实例2)
{
return 实例1的某个成员<实例2的某个成员;
}
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include<bits/stdc++.h>
using namespace std;
const int N = 2e6 + 10;
struct cow {
int p;
int maxnum;
}farmer[N];
bool cmp(cow farmer1,cow farmer2)
{
return farmer1.p<farmer2.p;
}
int main()
{
int m,n;
int sum = 0;
cin >> m>> n;
for (int i = 0; i < n; i++)
{
cin >> farmer[i].p>>farmer[i].maxnum;
}
sort(farmer,farmer+n,cmp);
//需要m牛奶
int mark=0;
while(farmer[mark].maxnum<m)
{
m-=farmer[mark].maxnum;
sum+=farmer[mark].p*farmer[mark].maxnum;
mark++;
}
sum+=farmer[mark].p*m;
cout<<sum<<endl;
return 0;
}