大佬饶命,只有A,B,C
题意:给你一个长度为n的一个序列,然后每次可以选择两个位置,可以用随机数x,y来替换这两个位置,但是他们的或运算结果必须相等,求经过无限次的替换,求数组和最小
思路: 怎么让数组和减小,首先0或运算任何数等于他本身,要让和减小,可以让0和他们或运算的结果替换,那么就变成了不断让两个数或运算变小就可,那么替换后的0就参与求和,每次就换少一个数,直至只有一个,换句话说,就是所有数的或运算值的结果就是答案
AC代码
#include<iostream>
#include<algorithm>
#include<cmath>
#include<string>
#include<cstring>
#include<cstdio>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
typedef long long ll;
using namespace std;
int t,n;
int a[105];
void solve()
{
int rs = a[1];
for(int i = 2 ; i <= n ; i++) rs |= a[i];
cout << rs << endl;
}
int main(){
IOS;
cin >> t;
while(t--){
cin >> n;
for(int i = 1 ; i <= n ; i++) cin >> a[i];
solve();
}
return 0;
}
题意:又给你一个长度为n的序列,然后消除所有的局部最大值(ai > ai - 1 && ai > ai + 1),题目提供了一种操作,每次可以选择一个位置的数替换成任何数,求最小需要操作的次数,然后输出操作后的数组
思路:表面上只需要替换掉所有的局部最大值就可以了,但是看到最后一个样例就是解决这个题的关键,假如按表面上的替换,结果是4,然而结果是2,问题出现在两个局部最大值中间只差一个元素的话,替换掉中间的值就可,就把表面上的两次变成了一个,如果存在这样的情况就替换两个中间的,其余的表面上的替换就可,替换的值用它相邻的最大值替换,避免后面的值受到前面替换的值的影响产生新的局部最大值
AC代码
#include<iostream>
#include<algorithm>
#include<cmath>
#include<deque>
#include<string>
#include<cstring>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<stack>
#include<cstdio>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define PII pair<int,int>
#define PDI pair<double,int>
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
int t,n;
const int maxn = 2e5+5;
int a[maxn];
vector <int> b; //所有局部最大值的下标
void solve()
{
b.clear();
int ans = 0;
for(int i = 2 ; i < n ; i++){
if(a[i] > a[i + 1] && a[i] > a[i - 1]){
b.push_back(i);
}
}
for(int i = 0 ; i < b.size() ; i++){
ans++;
//注意下标,避免越界
if(i + 1 < b.size() && b[i + 1] == b[i] + 2){ //存在相邻的局部最大值
int pos = (b[i] + b[i + 1]) / 2;
a[pos] = max(a[b[i + 1]],a[b[i]]); //替换成相邻最大值
i++; //可以跳到下下一个位置了
}
else a[b[i]] = max(a[b[i] + 1],a[b[i] - 1]); 表面替换
}
cout << ans << endl;
for(int i = 1 ; i <= n ; i++) cout << a[i] << " ";
cout << "\n";
}
int main(){
IOS;
cin >> t;
while(t--){
cin >> n;
for(int i = 1 ; i <= n ; i++) cin >> a[i];
solve();
}
return 0;
}
这个题要是没有那个不超过n次操作,假如问最小的话,难得上升一大截
题意:给你一个长度为n的序列,然后你可以选择三个下标 x,y,z (x < y < z) ,可以用Ay - Az 替换Ax,问不超过n次操作是否可以序列变成一个从小到大的序列
思路:首先考虑不可能的情况(解题关键),假如a[n - 1]大于a[n],由于n后面没有位置可选,所以直接就是不可能 ,假如a[n] < 0 , a[n - 1] < a[n],说明要想变成从小到大的序列,所以数必须都为负数,除原本已经从小到大排序,不管怎样,我们考虑最后一步替换,要把ax 变成 ay - az, ay - az > ay,替换后就不能满足 从小到大的排序,所以也是-1,所以最终可能的情况就都在a[n] >= 0 && a[n - 1] < a[n],由于操作次数又我们定夺,我们可以改变前面1 ~ n - 2之间的所有数,y = a[n - 1],z = a[n],y - z 肯定比最后两个数都小,而前面每个数都相等
AC代码
#include<iostream>
#include<algorithm>
#include<cmath>
#include<deque>
#include<string>
#include<cstring>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<stack>
#include<cstdio>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define PII pair<int,int>
#define PDI pair<double,int>
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
int t,n;
const int maxn = 2e5+5;
int a[maxn];
void solve()
{
if(a[n - 1] > a[n]) cout << -1 << endl;
else{
if(a[n] >= 0){
cout << n - 2 << endl;
for(int i = 1 ; i <= n - 2 ; i++)
cout << i << " " << n - 1 << " " << n << "\n";
}
else{
if(is_sorted(a + 1,a + 1 + n)) cout << 0 << endl;
//判断是否已经从小到大排序可以直接调用函数
else cout << -1 << endl;
}
}
}
int main(){
IOS;
cin >> t;
while(t--){
cin >> n;
for(int i = 1 ; i <= n ; i++) cin >> a[i];
solve();
}
return 0;
}