A. Nastya Is Reading a Book
题意: n个区间,每个区间范围不超过100,n不超过100。给一个位置k,1-(k-1)是遍历过的位置,求没有完全遍历完的区间。
k处于区间中时,表示区间没有遍历完。
思路:数据范围小,直接暴力

#include <bits/stdc++.h>
using namespace std;
pair <int, int> p[102];
int main(){
    int n, k, ans = 0;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%d%d", &p[i].first, &p[i].second);
    scanf("%d", &k);
    for(int i = 1; i <= n; i++){
        if(p[i].second < k){
            ans++;
        }
    }
    printf("%d\n", n-ans);
}

B. Nastya Is Playing Computer Games
题意:有n个井盖,每个井盖上有一个小石头。给出n和k,k表示刚开始在第k个井盖上方。有三种操作,左右移动,扔石头到任意一个井盖,下到井盖里拿金币。只有井盖上没有石头才能下井盖。求捡完全部金币的最小步数。
思路:规律题,我们考虑一下当前位置和相邻的任意一个位置,要想拿到这2个井盖的金币一共需要6次。其余的井盖需要(n-2)*3个步骤,还需要考虑这个人是从哪个方向走导致多出来的步数,两个取小即可。

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int n, k;
    scanf("%d%d", &n, &k);
    int ans = n * 3 + min(k - 1, n - k);
    printf("%d\n", ans);
    return 0;
}

C:题意,给了俩个矩阵,你可以无数次对A矩阵的子矩阵进行转置操作,问A是否可以变为B?
思路:考虑一下转置的特性,发现不在同一对角线的元素是无法交换位置的。我们直接对主对角线进行求和判断即可。

#include <bits/stdc++.h>
using namespace std;
int a[505][505], b[505][505];
map <int, int> mp[1010];
int main(){
    int n, m;
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            scanf("%d", &a[i][j]);
            mp[i+j-1][a[i][j]]++;
        }
    }
    bool flag = 1;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            scanf("%d", &b[i][j]);
            if(mp[i+j-1][b[i][j]] <= 0){
                flag = 0;
                break;
            }
            mp[i+j-1][b[i][j]]--;
        }
    }
    if(flag){
        puts("YES");
    }else{
        puts("NO");
    }
}

D:题意:给一个序列和一组交换序列(a,b),当且仅当a在b的前面(不允许有间隔),这两个数才能交换,问最后一个数最多能移动多少个位置。
解法:不会,阅读题解,用数组cnt[x]记录数x后面可以与其交换的数的数目,当这个数目刚好等于这个数和最后一个数的距离时,肯定有办法能把最后一个数换到x的位置,然后需要注意的是要一直更新最后一个数的位置,它的位置就是n-ans(即数列长度-已经移动的次数)。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5+10;
int p[maxn], cnt[maxn];
vector <int> v[maxn];
int main(){
    int n, m, x, y;
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= n; i++){
        scanf("%d", &p[i]);
    }
    for(int i = 1; i <= m; i++){
        scanf("%d %d", &x, &y);
        v[y].push_back(x);
    }
    for(int i = 0; i < v[p[n]].size(); i++){
        cnt[v[p[n]][i]]++;
    }
    int ans = 0;
    for(int i = n - 1; i >= 1; i--){
        if(n - i - ans == cnt[p[i]]){
            ans++;
        }else{
            for(int j = 0; j < v[p[i]].size(); j++){
                cnt[v[p[i]][j]]++;
            }
        }
    }
    printf("%d\n", ans);
    return 0;
}

E. Nastya Hasn’t Written a Legend
题意:有一个数组a和一个数组k,数组a一直保持一个性质:a[i + 1] >= a[i] + k[i]。有两种操作:1,给某个元素加上x,但是加上之后要保持数组a的性质。比如a[i]加上x之后,a[i + 1]<a[i] + k[i],那么a[i + 1]就变成a[i] + k[i],否则不变。同理,若a[i + 2]小于了现在的a[i + 1] + k[i + 1],那么a[i + 2]也变成a[i + 1] + k[i + 1],一直保持这个性质。第二章操作,询问数组a的区间[l, r]的区间和。
题解:https://www.cnblogs.com/pkgunboat/p/10527569.html
题解:来自上面的博主,容易发现,假设更改了x位置之后,恰好到位置y不需要更改元素,那么及其之后的位置肯定就不用更改了。所以,在查找这个位置的时候,我们可以二分查找。找到之后,对区间[x, y]进行操作。我们可以发现,区间[x, y]的数有规律。假设x位置的数是a[x],那么a[x + 1]是a[x] + k[x], a[x + 2]是a[x] + k[x + 1] + k[x + 2],以此类推。这个区间的和可以分为2部分:[y - x + 1]个a[x],和关于k的部分。可以发现,k[x]出现了(r - l + 1)次,k[x + 1]出现了(r - l)次,以此类推。那么怎么O(1)获得这个东西呢?我们先预处理k数组的前缀和(假设前缀和数组是b),那么我们再求b的前缀和(假设是数组c),那么c[i]就是出现了i次k[1],i - 1次k[2],以此类推。那么区间[x, y]中关于k的和就可以得出了:c[y] - c[x - 1] - [y - x + 1] * b[x]。前面c[y] - c[x - 1]可以O(1)算出,而后面的部分比较麻烦。怎么维护后面[y - x + 1] * b[x]这个部分呢?我们发现a[x]正好出现[y - x + 1]次,这样我们可以把a[x] - b[x]用一个懒标记维护,下放标记的时候区间的和为c[y] - c[x - 1] + (r - l + 1) * val (val是a[x] - b[x])。
这个算法的复杂度是nlog(n),我当时在想分块是不是可以维护,但估计会T。太菜了,完全没有状态了,只能看看题解写写,告辞。

#include <stdio.h>
#include <iostream>
using namespace std;
const int maxn = 1e6 + 10;
const long long INF = 1e18;
long long a[maxn], b[maxn], c[maxn];
struct node {
	int l, r;
	long long sum, tag;
}Tree[maxn << 2];

void push_up(int rt) {
	Tree[rt].sum = Tree[rt * 2].sum + Tree[rt * 2 + 1].sum;
}

void push_down(int rt) {
	if (Tree[rt].tag != -INF) {
		Tree[rt * 2].sum = (Tree[rt * 2].r - Tree[rt * 2].l + 1) * Tree[rt].tag + (c[Tree[rt * 2].r] - c[Tree[rt * 2].l - 1]);
		Tree[rt * 2].tag = Tree[rt].tag;
	}
	if (Tree[rt].tag != -INF) {
		Tree[rt * 2 + 1].sum = (Tree[rt * 2 + 1].r - Tree[rt * 2 + 1].l + 1) * Tree[rt].tag + (c[Tree[rt * 2 + 1].r] - c[Tree[rt * 2 + 1].l - 1]);
		Tree[rt * 2 + 1].tag = Tree[rt].tag;
	}
	Tree[rt].tag = -INF;
}

void build(int l, int r, int rt) {
	Tree[rt].l = l, Tree[rt].r = r;
	Tree[rt].tag = -INF;
	if (l == r) {
		Tree[rt].sum = a[l];
		return;
	}
	int mid = (l + r) >> 1;
	build(l, mid, rt * 2);
	build(mid + 1, r, rt * 2 + 1);
	push_up(rt);
}

void update(int L, int R, int l, int r, int rt, long long val) {
	if (L <= l && r <= R) {
		if (val != -INF) {
			Tree[rt].sum = (Tree[rt].r - Tree[rt].l + 1) * val + (c[Tree[rt].r] - c[Tree[rt].l - 1]);
			Tree[rt].tag = val;
		}
		return;
	}
	push_down(rt);
	int mid = (l + r) >> 1;
	if (L <= mid) update(L, R, l, mid, rt * 2, val);
	if (mid < R) update(L, R, mid + 1, r, rt * 2 + 1, val);
	push_up(rt);
}

long long query(int L, int R, int l, int r, int rt) {
	if (L <= l && r <= R) {
		return Tree[rt].sum;
	}
	push_down(rt);
	int mid = (l + r) >> 1;
	long long ans = 0;
	if (L <= mid) ans += query(L, R, l, mid, rt * 2);
	if (mid < R) ans += query(L, R, mid + 1, r, rt * 2 + 1);
	return ans;
}

int main() {
	int n, q;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%lld", &a[i]);
	}
	for (int i = 2; i <= n; i++) {
		scanf("%lld", &b[i]);
		b[i] += b[i - 1];
	}
	for (int i = 2; i <= n; i++) {
		c[i] = c[i - 1] + b[i];
	}
	build(1, n, 1);
	scanf("%d", &q);
	char op[10];
	int x, y;
	while (q--) {
		scanf("%s%d%d", op + 1, &x, &y);
		if (op[1] == '+') {
			int l = x;
			int r = n;
			long long temp = query(x, x, 1, n, 1);
			while (l < r) {
				//int mid = (l + r) >> 1;
				int mid = (l + r + 1) >> 1;
				long long temp1 = query(mid, mid, 1, n, 1);
				if ((temp + y + b[mid] - b[x]) > temp1) {
					l = mid;
				}
				else {
					r = mid - 1;
				}
			}
			//printf("************%d %d %d*********\n", x, l, temp + y - b[x]);
			update(x, l, 1, n, 1, temp + y - b[x]);
		}
		else {
			printf("%lld\n", query(x, y, 1, n, 1));
		}
	}
	//system("pause");
	return 0;
}