6135. 奶牛体检-枚举
农夫约翰的 N 头奶牛站成一行,奶牛 1 在队伍的最前面,奶牛 N 在队伍的最后面。
农夫约翰的奶牛也有许多不同的品种。
他用从 1 到 N 的整数来表示每一品种。
队伍从前到后第 i 头奶牛的品种是 ai。
农夫约翰正在带他的奶牛们去当地的奶牛医院进行体检。
然而,奶牛兽医非常挑剔,仅愿意当队伍中第 ii 头奶牛为品种 bibi 时对其进行体检。
农夫约翰很懒惰,不想完全重新排列他的奶牛。
他将执行以下操作恰好一次。
- 选择两个整数 l 和 r,使得 1≤l≤r≤N。反转队伍中第 l头奶牛到第 r头奶牛之间的奶牛的顺序。
农夫约翰想要衡量这种方法有多少效果。
对于每一个 c=0…N,请帮助农夫约翰求出使得恰好 c 头奶牛被检查的不同操作 (l,r)的数量。
两种操作 (l1,r1) 和 (l2,r2) 不同,如果 l1≠l2l 或者 r1≠r2。
输入格式
输入的第一行包含 N。
第二行包含 a1,a2,…,aN。
第三行包含 b1,b2,…,bN。
输出格式
输出 N+1 行,第 i 行包含使得 i−1 头奶牛被检查的不同操作 (l,r)的数量。
数据范围
1≤N≤7500,
1≤ai,bi≤N
输入样例1:
3
1 3 2
3 2 1
输出样例1:
3
3
0
0
样例1解释
如果农夫约翰选择 (l=1,r=1)(l=1,r=1),(l=2,r=2)(l=2,r=2) 或 (l=3,r=3)(l=3,r=3),则没有奶牛将会被检查。
注意这些操作并没有改变奶牛的位置。
以下操作会导致一头奶牛被检查。
- (l=1,r=2)(l=1,r=2):农夫约翰反转第一头和第二头奶牛的顺序,因此新队伍中每头奶牛的品种将为 [3,1,2][3,1,2]。第一头奶牛将会被检查。
- (l=2,r=3)(l=2,r=3):农夫约翰反转第二头和第三头奶牛的顺序,因此新队伍中每头奶牛的品种将为 [1,2,3][1,2,3]。第二头奶牛将会被检查。
- (l=1,r=3)(l=1,r=3):农夫约翰反转第一头,第二头和第三头奶牛的顺序,因此新队伍中每头奶牛的品种将为 [2,3,1][2,3,1]。第三头奶牛将会被检查。
输入样例2:
3
1 2 3
1 2 3
输出样例2:
0
3
0
3
样例2解释
三种导致 33 头奶牛被检查的可能操作为 (l=1,r=1)(l=1,r=1),(l=2,r=2)(l=2,r=2) 和 (l=3,r=3)(l=3,r=3)。
输入样例3:
7
1 3 2 2 1 3 2
3 2 2 1 2 3 1
输出样例3:
0
6
14
6
2
0
0
0
样例3解释
两种导致 44 头奶牛被检查的可能操作为 (l=4,r=5)(l=4,r=5) 和 (l=5,r=7)(l=5,r=7)。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 7510; // 定义数组的最大大小
int n; // 输入的数组长度
int a[N], b[N]; // 存储输入的两个数组
int ans[N]; // 存储每个可能的结果数量
int main()
{
scanf("%d", &n); // 输入数组长度 n
for (int i = 1; i <= n; i++) scanf("%d", &a[i]); // 输入数组 a 的元素
for (int i = 1; i <= n; i++) scanf("%d", &b[i]); // 输入数组 b 的元素
int cnt = 0; // 统计初始时 a[i] == b[i] 的数量
for (int i = 1; i <= n; i++)
if (a[i] == b[i]) // 如果 a[i] 和 b[i] 相等,则计数器 cnt 增加
cnt++;
// 遍历所有可能的区间 [l, r],并计算交换后的匹配数
for (int i = 1; i <= n; i++) // 枚举中心点 i
for (int j = 0; j < 2; j++) // 枚举区间长度(j=0 表示单点,j=1 表示两点)
{
int sum = cnt; // 初始化当前匹配数为初始匹配数 cnt
for (int l = i, r = i + j; l >= 1 && r <= n; l--, r++) // 扩展区间 [l, r]
{
// 更新匹配数:先减去原匹配,再加上新匹配
if (a[l] == b[l]) sum--; // 如果 a[l] 和 b[l] 原本匹配,则减少匹配数
if (a[r] == b[r]) sum--; // 如果 a[r] 和 b[r] 原本匹配,则减少匹配数
if (a[l] == b[r]) sum++; // 如果交换后 a[l] 和 b[r] 匹配,则增加匹配数
if (a[r] == b[l]) sum++; // 如果交换后 a[r] 和 b[l] 匹配,则增加匹配数
ans[sum]++; // 将当前匹配数 sum 的计数器加 1
}
}
// 输出结果:ans[i] 表示匹配数为 i 的情况出现的次数
for (int i = 0; i <= n; i++) printf("%d\n", ans[i]);
return 0; // 程序结束
}