数组

P5716 [深基3.例9] 月份天数

#include <cstdio>
int main()
{
    int days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    int y, m;
    scanf("%d%d", &y, &m);
    if (y % 4 == 0 && y % 100 != 0 || y % 400 == 0) days[1] = 29;
    printf("%d\n", days[m - 1]);  
    return 0;
}

P1046 [NOIP2005 普及组] 陶陶摘苹果

#include <cstdio>
int main()
{
    int h[10];
    for (int i = 0; i < 10; i++) scanf("%d", &h[i]);
    int t;
    scanf("%d", &t);
    int ans = 0;
    for (int i = 0; i < 10; i++) {
        if (t + 30 >= h[i]) ans++;
    }
    printf("%d\n", ans);
    return 0;
}

P1089 [NOIP2004 提高组] 津津的储蓄计划

#include <cstdio>
int main()
{
    int b[13];
    for (int i = 1; i <= 12; i++) {
        scanf("%d", &b[i]);
    }
    int save = 0;
    int money = 0;
    for (int i = 1; i <= 12; i++) {
        money += 300;
        money -= b[i];
        if (money < 0) {
            printf("%d\n", -i);
            break;
        }
        save += money / 100 * 100;
        money = money % 100;
    }
    if (money >= 0) {
        money += save / 5 * 6;
        printf("%d\n", money);
    }
    return 0;
}

P1428 小鱼比可爱

#include <cstdio>
int main()
{
    int n;
    scanf("%d", &n);
    int a[105];
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    for (int i = 1; i <= n; i++) {
        int x = 0;
        for (int j = 1; j < i; j++) {
            if (a[j] < a[i]) ++x;
        }
        printf("%d ", x);
    }
    return 0;
}

P1427 小鱼的数字游戏

#include <cstdio>
int main()
{
    int x;
    int a[105];
    int len = 0;
    while (scanf("%d", &x)) {
        if (x == 0) break;
        a[++len] = x;
    }
    for (int i = len; i >= 1; i--) printf("%d ", a[i]);
    return 0;
}

P1047 [NOIP2005 普及组] 校门外的树

#include <cstdio>
int main()
{
    int l, m;
    int road[10005];
    scanf("%d%d", &l, &m);
    for (int i = 0; i <= l; i++) road[i] = 1;
    for (int i = 0; i < m; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        for (int j = u; j <= v; j++) road[j] = 0;
    }
    int ans = 0;
    for (int i = 0; i <= l; i++) ans += road[i];
    printf("%d\n", ans);
    return 0;
}

P5728 [深基5.例5] 旗鼓相当的对手

#include <cstdio>
int c[1005], m[1005], e[1005];
int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; ++i)
        scanf("%d%d%d", &c[i], &m[i], &e[i]);
    int ans = 0;
    for (int i = 0; i < n; ++i)
        for (int j = i + 1; j < n; ++j) {
            int dc = c[i] - c[j];
            int dm = m[i] - m[j];
            int de = e[i] - e[j];
            int dsum = (c[i] + m[i] + e[i]) - (c[j] + m[j] + e[j]);
            if (dc >= -5 && dc <= 5)
                if (dm >= -5 && dm <= 5)
                    if (de >= -5 && de <= 5)
                        if (dsum >= -10 && dsum <= 10)
                            ans++;
        }
    printf("%d\n", ans);
    return 0;
}

P5729 [深基5.例7] 工艺品制作

#include <cstdio>
int a[25][25][25];
int main()
{
    int w, x, h;
    scanf("%d%d%d", &w, &x, &h);
    int q;
    scanf("%d", &q);
    int cur = w * x * h;
    while (q > 0) {
        q--;
        int x1, y1, z1, x2, y2, z2;
        scanf("%d%d%d%d%d%d", &x1, &y1, &z1, &x2, &y2, &z2);
        for (int i = x1; i <= x2; ++i)
            for (int j = y1; j <= y2; ++j)
                for (int k = z1; k <= z2; ++k) {
                    if (a[i][j][k] == 0) --cur;
                    a[i][j][k] = 1;
                }
    }
    printf("%d\n", cur);
    return 0;
}

P2550 [AHOI2001] 彩票摇奖

#include <cstdio>
int main()
{
    int n;
    scanf("%d", &n);
    int num[35] = {0};
    int award[10] = {0};
    for (int i = 0; i < 7; i++) {
        int id;
        scanf("%d", &id);
        num[id] = 1;
    }
    for (int i = 0; i < n; i++) {
        int hit = 0;
        for (int j = 0; j < 7; j++) {
            int id;
            scanf("%d", &id);
            if (num[id] == 1) hit++;
        }
        award[7 - hit]++;
    }
    for (int i = 0; i <= 6; i++) printf("%d ", award[i]);
    return 0;
}

P1554 梦中的统计

#include <cstdio>
int main()
{
    int m, n;
    scanf("%d%d", &m, &n);
    int cnt[10] = {0};
    for (int i = m; i <= n; i++) {
        int t = i;
        while (t > 0) {
            cnt[t % 10]++;
            t = t / 10;
        }
    }
    for (int i = 0; i <= 9; i++) printf("%d ", cnt[i]);
    return 0;
}

P1614 爱与愁的心痛

#include <cstdio>
const int N = 3e3+5;
int a[N];
int main()
{
	int n, m; scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
	// a[1]+...+a[m]
	// a[2]+...+a[m+1]
	// ...
	// a[n-m+1]+...+a[n]
	int ans = 300000;
	for (int i = 1; i <= n-m+1; i++) {
		int sum = 0;
		for (int j = 1; j <= m; j++) {
			sum+=a[i+j-1];
		}
		if (sum<ans) ans=sum;
	}
	printf("%d\n", ans);
    return 0;
}
#include <cstdio>
const int N = 3e3+5;
int a[N];
int main()
{
	int n, m; scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
	// a[1]+...+a[m]
	// a[2]+...+a[m+1]
	// ...
	// a[n-m+1]+...+a[n]
	int sum = 0;
	for (int i = 1; i <= m; i++) sum+=a[i];
	int ans = sum;
	for (int i = 2; i <= n-m+1; i++) {
		sum = sum-a[i-1]+a[i+m-1];
		if (sum<ans) ans=sum;
	}
	printf("%d\n", ans);
    return 0;
}

P2911 [USACO08OCT] Bovine Bones G

#include <cstdio>
int main()
{
    int cnt[100] = {0};
    int s1, s2, s3;
    scanf("%d%d%d", &s1, &s2, &s3);
    for (int i = 1; i <= s1; ++i)
        for (int j = 1; j <= s2; ++j)
            for (int k = 1; k <= s3; ++k)
                cnt[i + j + k]++;
    int ans = 3, mx = 0;
    for (int i = 3; i <= s1 + s2 + s3; ++i) {
        if (cnt[i] > mx) {
            mx = cnt[i];
            ans = i;
        }
    }
    printf("%d\n", ans);
    return 0;
}

P5731 [深基5.习6] 蛇形方阵

#include <cstdio>
const int N = 10;
int a[N][N];
int main()
{
	int n; scanf("%d", &n);
	int number = 0;
	// 一圈一圈填数,n/2圈
	for (int i = 1; i <= n / 2; i++) {
		// 左上角(i,i) 右下角(n-i+1,n-i+1)
		// 向右 (i,i)->(i,n-i)
		for (int j = i; j <= n - i; j++)
			a[i][j] = ++number;
		// 向下 (i,n-i+1)->(n-i,n-i+1)
		for (int j = i; j <= n - i; j++)
			a[j][n-i+1] = ++number;
		// 向左 (n-i+1,n-i+1)->(n-i+1,i+1)
		for (int j = n-i+1; j>=i+1; j--)
			a[n-i+1][j] = ++number;
		// 向上 (n-i+1,i)->(i+1,i)
		for (int j = n-i+1; j>=i+1; j--)
			a[j][i] = ++number;
	}
	// 如果n是奇数,还有一个中心点需要填数
	if (n%2==1) a[n/2+1][n/2+1]=++number;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) printf("%3d", a[i][j]);
		printf("\n");
	}
    return 0;
}

#include <cstdio>
int main()
{
    int n;
    scanf("%d", &n);
    int s[10][10] = {0};
    int x = 1;
    int y = 1;
    int dx[4] = {0, 1, 0, -1};
    int dy[4] = {1, 0, -1, 0};
    int d = 0;  // 右0下1左2上3,当前方向为右
    s[1][1] = 1;
    int num = 2;
    while (num <= n * n) {
        int xx = x + dx[d];
        int yy = y + dy[d];
        if (xx >= 1 && xx <= n && yy >= 1 && yy <= n && s[xx][yy] == 0) {
            x = xx;
            y = yy;
            s[x][y] = num;
            num++;
        } else {
            d = (d + 1) % 4;
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) printf("%3d", s[i][j]);
        printf("\n");
    }
    return 0;
}

P5732 [深基5.习7] 杨辉三角

#include <cstdio>
int main()
{
    int n;
    int a[25][25] = {0};
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        a[i][1] = 1;
        a[i][i] = 1;
        for (int j = 2; j <= i - 1; j++) 
            a[i][j] = a[i - 1][j] + a[i - 1][j - 1];
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= i; j++) printf("%d ", a[i][j]);
        printf("\n");
    }
    return 0;
}

P1789 [Mc生存] 插火把

#include <cstdio>
#include <algorithm>
using namespace std;
int main()
{
    int mp[105][105] = {0};
    int n, m, k;
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 0; i < m; ++i) {
        int x, y;
        scanf("%d%d", &x, &y);
        mp[x][y] = 1;
        for (int j = max(x - 2, 1); j <= min(x + 2, n); ++j) mp[j][y] = 1;
        for (int j = max(y - 2, 1); j <= min(y + 2, n); ++j) mp[x][j] = 1;
        for (int a = max(x - 1, 1); a <= min(x + 1, n); ++a)
            for (int b = max(y - 1, 0); b <= min(y + 1, n); ++b)
                mp[a][b] = 1;
    }
    for (int i = 0; i < k; ++i) {
        int x, y;
        scanf("%d%d", &x, &y);
        for (int a = max(x - 2, 1); a <= min(x + 2, n); ++a)
            for (int b = max(y - 2, 1); b <= min(y + 2, n); ++b)
                mp[a][b] = 1;
    }
    int ans = 0;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            if (mp[i][j] == 0) ++ans;
    printf("%d\n", ans);
    return 0;
}

P1319 压缩技术

#include <cstdio>
int main()
{
    int n;
    scanf("%d", &n);
    int num = 0;
    int x;
    int cnt = 0, sum = 0;
    while (sum != n * n) {
        scanf("%d", &x);
        for (int j = 0; j < x; j++) {
            printf("%d", num);
            cnt++;
            if (cnt == n) {
                printf("\n");
                cnt = 0;
            }
        }
        num = 1 - num;
        sum += x;
    }
    return 0;
}

P2615 [NOIP2015 提高组] 神奇的幻方

#include <cstdio>
int ans[50][50];
int main()
{
    int n;
    scanf("%d", &n);
    int x = 1, y = (n + 1) / 2;
    ans[x][y] = 1;
    for (int i = 2; i <= n * n; ++i) {
        if (x == 1 && y < n) {
            x = n;
            ++y;
        } else if (y == n && x > 1) {
            y = 1;
            --x;
        } else if (x == 1 && y == n) {
            ++x;
        } else if (x != 1 && y != n) {
            if (ans[x - 1][y + 1] == 0) {
                --x;
                ++y;
            } else ++x;
        }
        ans[x][y] = i;
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) printf("%d ", ans[i][j]);
        printf("\n");
    }
    return 0;
}

P2141 [NOIP2014 普及组] 珠心算测验

注意题目问的是 “其中有多少个数,恰好等于集合中另外两个(不同的)数之和?”,我们可以枚举每个数,去验证能否通过另外的两个数把它加出来。

#include <cstdio>
const int N = 105;
int a[N];
int main()
{
    int n; scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        // 验证a[i]是否能被另外两个数加出来
        bool ok = false;
        for (int j = 1; j <= n; j++) {
            for (int k = j + 1; k <= n; k++) {
                if (a[i] == a[j] + a[k]) {
                    ok = true; break;
                }
            }
            if (ok) break;
        }
        if (ok) ans++;
    }
    printf("%d\n", ans);
    return 0;
}

更进一步地,由于给出的正整数取值范围在 \(10000\) 以内,因此也可以先处理出任意取两个数能加出哪些值来,从而快速验证某个数是否能被另外两个数加出来。

#include <cstdio>
const int N = 105;
const int A = 10005;
bool vis[A];
int a[N];
int main()
{
    int n; scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }
    for (int i = 1; i <= n; i++) {
        for (int j = i + 1; j <= n; j++) {
            int sum = a[i] + a[j];
            if (sum < A) vis[sum] = true; // 超出值域的情况不需要考虑
        }
    }
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        if (vis[a[i]]) ans++;
    }
    printf("%d\n", ans);
    return 0;
}

P1904 天际线

记录下轴上每个点的楼房高度的最大值,每个转折点的出现是由于最大高度的变化,所以最后将坐标从左往右枚举一遍,如果该点的高度与前一个点有差距,就说明是转折点,需要输出
考虑如下情况:
如果有两个相邻的楼房三元组,高度信息相同,前者的右端点坐标和后者的左端点坐标刚好差 1,此时这两个点高度没有发生变化,但这两个点都是转折点
针对这个问题,我们可以将原坐标体系放大到 2 倍,让原来的 x 和 x+1 在新坐标体系下分别为 2x 和 2x+2,这样 2x 和 2x+1 之间以及 2x+1 与 2x+2 之间都会存在高度差,从而解决了上面提到的问题

#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 20005;
int H[MAXN];
int main()
{
    int l, h, r;
    while (scanf("%d%d%d", &l, &h, &r) != -1) {
        for (int i = l * 2; i <= r * 2 ; i++) H[i] = max(H[i], h);
    } 
    for (int i = 2; i < MAXN; i++)
        if (H[i] != H[i - 1]) printf("%d %d ", i / 2, H[i]);
    return 0;
}

STL vector

动态数组是大小可以在运行过程中改变的数组。在 C++ 中最流行的动态数据是 vector,可以像普通数组一样使用它。

下面的代码创建了一个空的 vector 然后向里面添加了三个元素:

vector<int> v;
v.push_back(3); // [3]
v.push_back(2); // [3,2]
v.push_back(5); // [3,2,5]

此时,可以像普通数组一样访问里面的元素:

printf("%d %d %d\n", v[0], v[1], v[2]); // 3 2 5

函数 size 返回 vector 的元素数量。下面的代码遍历整个 vector 并输出每个元素:

for (int i = 0; i < v.size(); i++) {
	printf("%d\n", v[i]);
}

一种更简洁的遍历方式如下:

for (int x : v) {
	printf("%d\n", x);
}

这种 for 循环被称为 range-based for,每次循环它会按顺序把容器中的元素赋值给循环变量。更进一步,如果不想手动写出容器中元素的类型,可以使用 auto 关键字自动推导元素类型:

for (auto x : v) { // 这里的v因为是vector<int>,所以auto会推导出int
	printf("%d\n", x);
}

注意 size 的返回值类型是 size_t,是一种无符号整型,无符号整型不能表示负数。因此对于下面的代码:

#include <iostream>
#include <vector>
using std::cout;
using std::vector;
int main()
{
	vector<int> v;
	cout << v.size() << "\n"; // 0
	cout << v.size() - 1 << "\n"; // 18446744073709551615
	cout << int(v.size()) - 1 << "\n"; // -1
	return 0;
}	

至于 -1 为什么会变成 18446744073709551615,这和整数在计算机中的存储方式有关,会在后面讲到。这告诉我们如果想对 size 的返回结果涉及减法运算,可以先将其做类型转换,之后再做减法。这一点在倒序遍历 vector 时很重要:

for (int i = int(v.size()) - 1; i >= 0; i--) {
	printf("%d\n", v[i]);
}

上面的代码如果没有将 v.size() 转换成 int 类型,就会在 vector 为空时导致死循环。

函数 back 返回 vector 中的最后一个元素,函数 pop_back 删除最后一个元素:

vector<int> v; v.push_back(5); v.push_back(2);
printf("%d\n", v.back()); // 2
v.pop_back();
printf("%d\n", v.back()); // 5

下面的代码在创建 vector 时用五个元素初始化:

vector<int> v = {2, 4, 2, 5, 1};

另一种创建 vector 的同时给元素赋初始值的方式:

vector<int> v1(10); // 大小为10,每个元素初始值为0
vector<int> v2(10, 5); // 大小为10,每个元素初始值为5

函数 resize(n) 用于将调整 vector 的大小调整至 n。如果 n 小于当前的大小,会保留前 n 个元素,销毁多出来的部分。如果 n 大于当前的大小,会在末尾补足若干个元素使得新的大小变成 n,如果调用的是 resize(n,val),会用 val 来补足,如果不指定 val,就用默认的初始化元素。

vector<int> v;
for (int i = 1; i < 10; i++) v.push_back(i);
v.resize(5); // [1,2,3,4,5]
v.resize(8, 100); // [1,2,3,4,5,100,100,100]
v.resize(12); // [1,2,3,4,5,100,100,100,0,0,0,0]

习题:P5727 【深基5.例3】冰雹猜想

解题思路

注意 \(n \le 100\) 只是一开始的 \(n\),变化过程中可能会涉及不止 \(100\) 个中间数,所以不能只开大小 \(100\) 的数组。这里可以使用 vector 来记录中间的数,输出时倒过来输出即可。

#include <cstdio>
#include <vector>
using std::vector;
int main()
{
	int n; scanf("%d", &n);
	vector<int> ans; // 定义一个里面元素是int类型的动态数组
	// 一般不用vector<char> vector<bool>
	// 此时是没有ans[0]...的
	while (n!=1) {
		// 把n添加进ans
		ans.push_back(n);
		if (n%2==0) {
			n/=2;
		} else {
			n = 3 * n + 1;
		}
	}
	// 把n添加进ans
	ans.push_back(n);
	// ans.size()
	
	// 尽量不要对size()直接运算,比如 xxx.size()-1
	// for (int i=0;i<ans.size();i++) { printf("%d ",ans[i]); }
    // for (int i=ans.size()-1;i>=0;i--) { printf("%d ",ans[i]); }
    // 尽量不要像上面这样写ans.size()-1
    
	int len = ans.size();
	for (int i=len-1; i>=0; i--) {
		printf("%d ", ans[i]);
	}
	return 0;
}

例题:P3613 【深基15.例2】寄包柜

超市里有 \(n \ (n \le 10^5)\) 个寄包柜。每个寄包柜格子数量不一,第 \(i\) 个寄包柜有 \(a_i \ (a_i \le 10^5)\) 个格子,不过并不知道各个 \(a_i\) 的值。对于每个寄包柜,格子编号从 \(1\) 开始,一直到 \(a_i\)。现在有如下 \(q\) 次操作:
1)1 i j k:在第 \(i\) 个柜子的第 \(j\) 个格子存入物品 \(k \ (0 \le k \le 10^9)\)。当 \(k=0\) 时,说明清空该格子。
2)2 i j:查询第 \(i\) 个柜子的第 \(j\) 个格子中的物品是什么,保证查询的柜子存过东西。
已知超市里共计不会超过 \(10^7\) 个寄包格子,\(a_i\) 是确定然而未知的,但是保证一定不小于该柜子存物品请求的格子编号的最大值。当然,也有可能某些寄包柜中一个格子都没有。

分析:可以建立一个二维数组,s[i][j] 记录第 \(i\) 个柜子中第 \(j\) 个格子中的物品。根据本题的数据规模,需要定义一个大小为 \(10^5 \times 10^5\)int 数组(\(4 \times 10^{10}\) 字节,大约 40GB),显然会超出内存限制。

这里可以用 vector 来解决这个问题。寄包柜最多 \(10^5\) 个,所以可以开一个 \(10^5\) 的数组,但是由于每个寄包柜的格子数不一定,因此数组中的每个元素(每个寄包柜)用一个 vector 来存储,这样就解决了空间的问题。

#include <cstdio>
#include <vector>
using std::vector;
const int N = 1e5 + 5;
vector<int> v[N];
int main()
{
	int n, q; scanf("%d%d", &n, &q);
	for (int i=1;i<=q;i++) {
		int op; scanf("%d", &op);
		if (op==1) {
			int x,y,z; scanf("%d%d%d", &x,&y,&z);
			// resize()调整动态数组大小
			if (v[x].size()<=y) v[x].resize(y+1);
			v[x][y]=z;
		} else {
			int x,y; scanf("%d%d",&x,&y);
			printf("%d\n", v[x][y]);
		}
	}
    return 0;
}

如果要定义由 10 个动态数组组成的一个二维数组,可以写为 vector<int> v[10]。甚至动态数组还可以嵌套,定义一个两个维度都不定长的二维数组 vector<vector<int>> v

posted @ 2023-07-24 13:37  RonChen  阅读(53)  评论(0编辑  收藏  举报