一个只有两个数的数组,选择数组中的任意两个数,计算它们差值的绝对值并加入数组
给定一个长度为n的数组,该数组经过了n-2次以上操作,问原数组中的数?(输出两个中的任意一个)
由于加入数组的数都是正数,所以数组中的负数一定是原数
若数组中的数都是正数,由于每次计算的都是两者之间差值的绝对值,该值一定小于两数中较大的数。所以数组中最大的数一定是原数
#include
#include
using namespace std;
const int N = 110;
int T, n, a[N];
int main()
{
cin >> T;
while ( T -- )
{
cin >> n;
for (int i = 0; i < n; ++ i ) cin >> a[i];
int mn = *min_element(a, a + n);
int mx = *max_element(a, a + n);
if (mn < 0) cout << mn << endl;
else cout << mx << endl;
}
return 0;
}
对于长度为n的数组,若数组中的数分别是1~n中的所有数,那么该数组为n的全排列
给定长度为n的全排列,交换数组中的两个数,使得数组的子数组中,全排列数量最小
根据全排列的性质,1. 数组中的数不能重复,由于原数组本身就是全排列,所以其子数组中不会出现重复的数,故无法往这个方向构造。2. 长度为n的数组中不可能出现大于等于n+1的数,根据这个性质,我们可以构造一种情况,使得子数组出现n或者大于子数组长度的数
继续考虑,长度大于2的全排列中,一定会出现1与2。由于子数组必须是连续的这个性质,原数组1到2之间的所有数必须被包含
比如:1 3 2 5 4,前三个数构成的子数组1 3 2是一个全排列,其长度大于2,那么一定会包含原数组中1到2之间的数。而1到2之间的数为3,是一个小于等于数组长度的数,若1到2之间的数为一个大于数组长度的数,比如1 4 2 5 3或者1 5 2 3 4,前三个数构成的子数组不再是全排列
所以,无论如何选取子数组,子数组中一定有两个子数组是全排列,它们的长度为1和n。剩下的子数组,我们需要构造一种情况,使得原数组的1到2之间存在大于子数组长度的数。要使所有子数组的全排列数量最小,将n放入1到2之间,此时原数组的所有子数组中只存在两个全排列
因此,这道题的做法是:找出1,2和n的位置,若n不在1和2之间,将n与1(或2)交换
将 a [ i ] a[i] a[i]作为p数组的下标,用p数组存储 a [ i ] a[i] a[i]在a数组中的下标,即 p [ a [ i ] ] = i p[a[i]] = i p[a[i]]=i
最后将1,2,n三者的下标进行排序,输出n的下标与中间的下标
#include
#include
using namespace std;
const int N = 2e5 + 10;
int T, a[N], p[N], n;
int main()
{
cin >> T;
while ( T -- )
{
cin >> n;
int i1, i2, in;
for (int i = 1; i <= n; ++ i )
{
cin >> a[i];
p[a[i]] = i;
}
int b[] = { p[1], p[2], p[n] };
sort(b, b + 3);
cout << b[1] << ' ' << p[n] << endl;
}
return 0;
}
参考了灵神的思路与代码,对比自己的代码后,不得不说,灵神的代码是真的简洁
给定矩阵的n和m,矩阵中的数为1~ n ∗ m n*m n∗m,构造一个矩阵,使得(上下左右)相邻的数,绝对值为非质数
矩阵的构造一般有几种:1. 横着构造 2. 竖着构造 3. 斜着构造 4. 染色构造(每次构造不相邻的格子)
这题可以横着构造,若n为4,m为4,先构造第一行1 2 3 4,这样一行中的每个数相差1,满足题意
再构造剩余行:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
每一列中,相邻元素相差4,满足题意。若交换每一行的位置,矩阵依然满足题意,因为每一列相邻元素的差值为m的倍数,m为非质数,其倍数一定是非质数。若m为质数,其两倍以上的数才是非质数
若n为4,m为5
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
每一行中的相邻元素相差1,满足题意,每一列的相邻元素相差5,不满足题意。考虑行的交换
11 12 13 14 15
1 2 3 4 5
16 17 18 19 20
6 7 8 9 10
此时满足题意,若m和n都为5
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
交换:
1 2 3 4 5
11 12 13 14 15
21 22 23 24 25
6 7 8 9 10
16 17 18 19 20
可以发现,当m为质数时,要使每一列的相邻元素相差非质数,这个差值必须是m的两倍或者两倍以上
也就是将:奇数行变成相邻行,偶数行变成相邻行,使得矩阵的上一半为原来的奇数行,下一半为原来的偶数行
此时矩阵的两部分都满足题意,但是上半部分和下半部分的相邻行,如果本来就是相邻行呢?如:
1 2 3 4 5
11 12 13 14 15
6 7 8 9 10
16 17 18 19 20
11所在行与6所在行本来就是相邻行,此时矩阵中只有这两行不满足题意。将奇数行的第一行1与偶数行的最后一行16作为相邻行,那么一定满足题意
6 7 8 9 10
16 17 18 19 20
1 2 3 4 5
11 12 13 14 15
即,交换上下两个部分,偶数行在上,奇数行在下
综上,这题的构造方式是:
#include
using namespace std;
const int N = 1010;
int a[N][N];
int T, n, m;
int main()
{
cin >> T;
while ( T -- )
{
cin >> n >> m;
for (int i = 1, x = 1; i <= n; ++ i )
for (int j = 1; j <= m; ++ j )
a[i][j] = x ++ ;
for (int i = 2; i <= n; i += 2)
{
for (int j = 1; j <= m; ++ j )
cout << a[i][j] << ' ';
cout << endl;
}
for (int i = 1; i <= n; i += 2)
{
for (int j = 1; j <= m; ++ j )
cout << a[i][j] << ' ';
cout << endl;
}
}
return 0;
}
给定一个之包含1和-1的序列,从左到右走完这个序列,在不越界的情况下,每一步可以向左或向右走。将走过位置的数值累加,即 s u m + = a [ i ] sum += a[i] sum+=a[i],满足sum始终大于等于0,并且最后为0
问:将某个位置的数改为相反数后,是否满足题意?
判断YES或NO的题,先考虑NO的情况
若数组长度为奇数,那么sum最后的值一定不为0,输出NO
由于这题能往回走,考虑出现连续的1或者-1时,往回走1次对sum的影响
若出现k个连续的1,往回走1次,sum += (k - 2) * 2 + 2
若出现k个连续的-1,往回走1次,sum += (k - 2) * -2 + -2
所以只要k大于等于2,不论往回走几次,对sum的影响为一个偶数的变化,且最少变化2或-2
只要出现了连续的1,那么sum就能达到正无穷,只要连续的1之后存在连续的-1,那么sum就能回到0。所以连续1和连续-1之间的情况不需要考虑,因为无论情况怎样,最后都一定是0。所以只要保证连续1之前与连续-1之后,序列由( )
组成。若出现( ))
或者(( )
,则视为不合法
那如何用代码实现呢?实现方式很巧妙,之前自己写了三份不同的,一大堆ifelse条件判断,依然是漏了一些情况。心态崩了,只好借鉴灵神的思路
假设用字符串保存括号序列,从0下标开始。规定偶数下标必须保存(
,奇数下标必须保存)
,即序列()()()()...
。若真实序列的偶数下标保存)
,那么记录该下标,同理,真实序列的奇数下标保存(
,也记录该下标
所以,被记录的下标中,偶数下标为)
,奇数下标为(
。若最小值为奇数下标,并且最大值为偶数下标,说明真实序列中先出现((
最后出现))
,此时序列合法
若最小值与最大值都为偶数下标,说明真实序列中,第一次出现的连续括号与最后一次出现的连续括号都是))
,显然不合法
若最小值与最大值都为奇数下标,说明真实序列中,第一次出现的连续括号与最后一次出现的连续括号都是))
,也同样不合法
由于被记录的下标中,要取出最大与最小值,并且每次的询问操作还是叠加的,这里用set保存被记录的下标,begin()和人begin()返回的就是最小与最大值。每次判断要反转的括号是否在set中,若不在,则说明该下标上的括号原本是正确的,反转后将该下标加入set,若存在,将该下标从set中删除
#include
#include
using namespace std;
const int N = 2e5 + 10;
char str[N];
int n, q;
set<int> s;
int main()
{
cin >> n >> q >> str;
char a[3] = "()";
for (int i = 0; i < n; ++ i )
if (str[i] != a[i & 1])
s.insert(i);
while ( q -- )
{
int x;
cin >> x;
if (s.count(-- x)) s.erase(x);
else s.insert(x);
if (n & 1) cout << "NO" << endl;
// 最小的是右括号(偶数),最大的是左括号(奇数)
else if (s.size() && ((*s.begin() % 2 == 0) || (*s.rbegin() % 2))) cout << "NO" << endl;
else cout << "YES" << endl;
}
return 0;
}