专题班前缀和练习题 - F - 牛牛的猜球游戏
要求 [L,R] 区间的运算,怎么在 O(1) 的时间内,利用 [1,R] 与 [1, L-1] 的结果算出来
A 思路:矩阵
这是 N 个杯子,N 个球,建立一个 N * N 的矩阵,每进行一次操作,杯子交换也好,球移动也好,就是进行一次矩阵乘法运算。所以不管运算多少次,只要记得 [1, L-1] 和 [1,R] 的操作。
乘 [1,R], 除 [1, L-1]即可。当然,除在矩阵中,就是乘逆矩阵。矩阵代码会很麻烦。
B 思路:群论
把(0,1,2,3,4,5,6,7,8,9)想成一个圈
无论怎么换,都是在这个圈中对元素进行交换。找到某种方法,对区间 [1, L-1] 的操作取消即可。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 20;
int s[maxn][20], n, m, a, b, ans[20], tmp[20];
int main(){
//freopen("input.txt", "r", stdin);
scanf("%d%d", &n, &m);
memset(s, 0, sizeof(s));
for(int j = 0; j <= 9; j++)
s[0][j] = j;
for(int i = 1; i <= n; i++){
scanf("%d%d", &a, &b);
for(int j = 0; j <= 9; j++)
s[i][j] = s[i - 1][j];
swap(s[i][a], s[i][b]);
}
for(int k = 1; k <= m; k++){
scanf("%d%d", &a, &b);
for(int l = 0; l <= 9; l++)
tmp[s[a-1][l]] = l;
for(int l = 0; l <= 9; l++)
ans[l] = tmp[s[b][l]];
for(int l = 0; l <= 9; l++)
printf("%d%c", ans[l], l == 9 ? '\n': ' ');
}
return 0;
}
for(int _ = 1; _ <= m; _++){
scanf("%d%d", &a, &b);
for(int j = 0; j <= 9; j++)
for(int k = 0; k <= 9; k++)
if (s[a - 1][j] == s[b][k]){
ans[k] = j;
break;
}
for(int l = 0; l <= 9; l++)
printf("%d%c", ans[l], l == 9 ? '\n': ' ');
}第一种代码,就是说,去找还原。
第二种代码,就是暴力询问,在 [1, R] 之后,去找到 [L-1] 的杯子。
第二种可能好理解一些,但是多了一个常数级别。
查看10道真题和解析
