目录
A. Palindromic Indices
题目翻译: 给定一个回文串,问:可以最多拿走多少字符,使字符串仍然为回文串
思路:取一个字符串 t 为中间值,向左枚举,当枚举的字符串不等于中间字符串时,结束循环
n 奇数时:取 t = n/2,t 为正中间的字符串,去掉的字符串应该与中间的字符串相等时,可以去除该字符串,因为左右相等,所以去除左右是一样的因此 res += 2,使的去掉后的字符串仍然为回文字符串
n 偶数时:取t = n/2 ,t 为正中间一对字符串中的一个,向左枚举与上述操作类似
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
typedef long long LL;
const int N = 2e5+10;
int T;
void solve()
{
int cnt = 0;
int n;
cin >> n;
string s;
cin >> s;
if(s.size()%2)
{
char t = s[s.size()/2];
cnt = 1;
for(int i = s.size()/2-1; i >= 0; i -- )
if(s[i] == t) cnt += 2;
else break;
}
else
{
char t = s[s.size()/2];
for(int i = s.size()/2-1; i >= 0; i -- )
if(s[i] == t) cnt += 2;
else break;
}
cout << cnt << endl;
return;
}
int main()
{
scanf("%d", &T);
while(T -- )
solve();
return 0;
}
B. AND Sorting
B. AND Sorting
题目翻译:给定数组数组p,其中元素为 0~n-1,随机顺序但数组元素不重复,存在一个 x ,使得当 p[i] & p[j] == x 时,可以交换 p[i] 和 p[j] ,请问:求出最大的 x 使得交换过的数组为升序
思路:
(1)判断最大的 x :当两个元素交换时,有两种方式交换,直接交换 ( swap(p[i], p[j]) ) ,通过第三者交换 (swap(p[i], p[t]) , swap(p[t], p[j] ) ,第一种直接交换 x = p[i] & p[j] ,第二种 x = p[i] & p[t] & p[j] ,很明显第二种的 x <= 第一种的 x ,& p[t] 有风险,所以我们可以确定大致思路为,将要交换的值 & 起来
(2)如果要交换 p[i] & p[j] == x , p[k] & p[l] == x,可知 x 的 1 的位置与上述的四个数的 1 的位置重叠,即,可以表示为 p[i] & p[j] & p[k] & p[l] = x,如此将所有要交换的值 & 起来即可
因为元素为 0~n-1恰好为索引值,所以我们排列好的数组的值,因该与索引值一致,所以,原数组中与索引值不一致的数为要交换的数,结果为,将所有值与索引不一致的数 & 与 起来即可
初始化:将 x 可能用到的位置为 1 ,1 << 20 二进制表示为 1 后面19个0,(1 << 20) - 1 为 19位1,大于 2e5
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
typedef long long LL;
const int N = 2e5+10;
int T;
void solve()
{
int n;
scanf("%d", &n);
vector<int> a(n+10), b;
for(int i = 0; i < n; i ++ )
scanf("%d", &a[i]);
int x = (1 << 20) - 1;
for(int i = 0; i < n; i ++ )
if(a[i] != i) x &= a[i];
cout << x << endl;
return;
}
int main()
{
scanf("%d", &T);
while(T -- )
solve();
return 0;
}
C. LIS or Reverse LIS?
题目翻译:给数组a,任意排序,使得最大上升子序列的值 LIS(a) (LIS1),反转后的最大上升子序列LIS(a') (LIS2) ,二者取 min 的数最大
思路:
解读题意:查找最大上升子序列与最大下降子序列取 min 的最大值,即两序列所含数目应尽可能的接近
(1)两序列最多只能包含一个公共的索引(即,最大值的索引)
(2)给定一个数值,他只能有三个位置可以去,LIS1,LIS2,LIS1&LIS2(只在LIS1中出现,只在LIS2中出现,即在LIS1中出现又在LIS2中出现),
(3)若为本数值的数的个数大于等于2,说明可以令其中一个取LIS1,令另一个取LIS2,即LIS1与LIS2中都存在此数,若此数的个数为1,说明他只能取一个序列中
所以答案为 两个都能去的数值 + 【(唯一的数个数为奇数)唯一的数的个数/2 (下取整) + 1 或(唯一的数个数为偶数)唯一的数的个数/2】
第二项合并为:(唯一的数的个数+1)/2(下取整)
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
typedef long long LL;
const int N = 2e5+10;
int T;
void solve()
{
int n;
scanf("%d", &n);
vector<int> a(n+10), b;
for(int i = 0; i < n; i ++ )
scanf("%d", &a[i]);
int x = (1 << 20) - 1;
for(int i = 0; i < n; i ++ )
if(a[i] != i) x &= a[i];
cout << x << endl;
return;
}
int main()
{
scanf("%d", &T);
while(T -- )
solve();
return 0;
}