题目大意:对A和B序列进行如题二三行操作,至少需要多少次可以使A+B=C。(第一行,第二行,第三行)
思路:先创建一个三行n列的数组a[3][n]。然后创建一个b[N]数组,用来储存a[2][i]-a[1][i]的数据(第三行的数据减去第二行的对应数据),然后和a[1][i]比较。定义op(对第二行操作的次数)定义op2(对第一行操作的次数)。对第二行操作(可理解为转动第二行,就像密码箱的密码锁一样),然后每操作一次就让第三行减去第二行,再将结果和第一行进行对比,如果不行就对第一行操作(最多转n次,因为第n次的时候就恢复到原样了)。如果n次对第一行操作之后仍然无法配对,就对第二行进行下一轮操作。如果行,就输出对第一行的操作数和对第二行的操作数(也就是op+op2),如果都不行,那就输出-1
因为题目条件限制有A,B,C中的元素都大于1,所以当b[i]<=0时直接排除,然后对第二行再进行操作。如果这些元素都>=1,就开始和第一行进行比较。
这里用num来做计数器(有配对的就num++,否则重置num=0,如果num==n-1,就说明b数组和第一行全部配对,就说明条件成立,flag=1。输出op+op2)
每一次对第一行操作都会op2++。
用h作为b数组的下标,(z+op2)%n来表示对第一行操作后的各元素下标,如果不符合,同样h和z重置为0。
时间复杂度大概是3*n+n^3,好像quo实有点大了,救救阔怜的大一孩子叭T^T
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int a[3][N];
int b[N];
int main() {
int n;
cin >> n;
int i, j,op=0,k,op2=0;//op为对第二行操作次数,op2为对第一行操作次数
int flag;//标志变量,1代表符合条件,0代表不符合
for (i = 0; i < 3; i++) {
for (j = 0; j < n; j++) cin >> a[i][j];
}//输入数据
for (j = 0; j < n; j++) {
flag = 1;
for (i = 0; i < n; i++) {//算出b[i]
b[i] = a[2][i] - a[1][i];
if (b[i] <= 0) {
flag = 0;
break;
}//如果某一项<=0 退出,直接进入下一轮,对第二行进行操作(可降低时间复杂度)
}
if (flag == 0) {
int t = a[1][0];//保存第一个元素
for (i = 0; i < n - 1; i++) {
a[1][i] = a[1][i + 1];
}//所有的数据都往前移动
a[1][n - 1] = t;//让最后一个数据变成原数组的第一个数据
op++;//对第二行的操作次数增加
continue;//跳到下一组(下面的所有程序不执行,直接进入下一组(剪枝)
}//转动第二行
else {
op2 = 0;//操作第一行的次数
int h=0,z=0,num=0;
while (op2 < n) {
if (b[h] != a[0][(z+op2)%n]) {//(z+op2)%n计算操作后的下标位置
op2++;
h = 0;
z = 0;
flag = 0;
num = 0;
continue;
}//如果某一项不匹配,对第一行操作,并且对h,z重置
else {
h++;
z++;
num++;
}//如果匹配就比对下一个数
if (num == n-1 ) {
flag = 1;
break;
}//如果n轮都顺利进行那就flag=1,退出
}
}
if (flag == 1) {
cout << op + op2;
break;
}//如果flag=1 输出答案
else {
int t = a[1][0];
for (i = 0; i < n - 1; i++) {
a[1][i] = a[1][i + 1];
}
op++;
a[1][n - 1] = t;
}//否则对二再进行操作
}
if (flag == 0) cout << "-1";//如果n轮下来都不匹配,就输出-1
return 0;
}