A. Prof. Slim
题意 : 有一个 a 数组,在 之间, 将 和 数值的符号交换,可以使得数组 a 是否为非降序的数组。
从左往右找大于 0 的位置和从右往左找 小于 0 的位置,进行符号交换,最后判断数组 a 是否非降序。
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1e5+10;;
int a[N], b[N];
int main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
for(int i=0; i<n; i++) cin>>a[i];
int l = 0, r = n-1;
while(l < r){
while(l < n && a[l] < 0){
l++;
}
while(r >= 0 && a[r] > 0){
r--;
}
if(l < r){
a[l] = -a[l];
a[r] = -a[r];
}
}
if(n == 1){
cout<<"YES"<<endl;
}else{
bool flag = true;
for(int i=1; i<n; i++){
if(a[i-1] > a[i]){
flag = false;
break;
}
}
if(flag) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
return 0;
}
B. Dorms War
题意 : 给一个长度为 n 的字符串 s , 一个长度为 k 的特殊字符串 c ,找到所有 位置的字符在特殊字符 c 中, 位置的字符会被删除, 最多操作几次。求2个特殊字符中间的距离
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
int main() {
int t;
cin>>t;
while(t--){
int n;
string s;
cin>>n>>s;
int k;
bool st[26]; // 保存特殊字符
memset(st, false, sizeof st);
char c;
cin>>k;
for(int i=0; i<k; i++){
cin>>c;
st[c-'a'] = true;
}
vector<int> p;
p.push_back(0);
for(int i=0; i<n; i++){
if(st[s[i]-'a']){ // 记录特殊字符的位置
p.push_back(i);
}
}
int res = 0;
for(int i=1; i<p.size(); i++){
res = max(res, p[i]-p[i-1]);
}
cout<<res<<endl;
}
return 0;
}
C. Where is the Pizza?
题意:给 2个数组, 数组a 和数组 b,数组 d 表示 时, 可以选择 , 时, 就选择了 中的一个,求 数组有多少种组合。 分情况讨论
- , 表明 ;
- , 表明 ; 只有在 时, 可以提供 的答案。
例如 (1, 2), (2, 3),(3, 4),(4,1), 第一个坐标为 , 第二个坐标为 b,
d数组 1 0 0 0
或 0 2 0 0
或 0 0 3 0
或 0 0 0 4
在这个循环中,只有一个位置被确认,其他位置也会被确认。
只有在全部为 0 的情况可以提供 * 2 的组合
若有 个连通块没有被标识, 答案就是 。 可以使用并查集来做连通块是否被标识, 如果有被标识,将连通块挂到 0 下面。
#include <iostream>
#include <cstring>
#include <vector>
#include <set>
using namespace std;
const int N = 1e5+10;
int a[N], b[N], d[N], p[N];
int find(int u){
if(u != p[u]){
p[u] = find(p[u]);
}
return p[u];
}
int main() {
int t;
cin>>t;
while(t--){
int n;
cin>>n;
for(int i=0; i<n; i++) cin>>a[i];
for(int i=0; i<n; i++) cin>>b[i];
for(int i=0; i<n; i++) cin>>d[i];
// 初始化并查集
for(int i=0; i<=n; i++) p[i] = i;
for(int i=0; i<n; i++){
if(d[i] != 0){ // d[i] 不为零,证明有一个为被确定了,在这个连通快的数据都被确定了,挂到 0 下面
p[find(0)] = find(d[i]);
}
}
for(int i=0; i<n; i++){
if(a[i] == b[i]){ // a[i] === b[i], 同样
p[find(0)] = find(a[i]);
}
}
for(int i=0; i<n; i++){ // a 和 b 合并
p[find(a[i])] = find(b[i]);
}
set<int> set;
for(int i=1; i<=n; i++){
if(find(0) == find(i)) continue;
set.insert(find(i)); // 记录未被标记的父节点
}
long long res =1;
int mod = 1e9+7;
for(int i=0; i<set.size(); i++){
res *=2;
res%=mod;
}
cout<<res<<endl;
}
return 0;
}
D. Very Suspicious
题意: 很多六边形,需要 n 个小三角形, 最少需要切多少刀。
多画一些可以得到 线条数为下标,数值为增加三角形的数量, 从 1 开始, [0, 2, 4, 4, 6, 8, 8, 10, 12] ... 这样的规律。 使用 p 数组, 下标为线条数, 数值为三角形的总数量,需要求 n 个三角形,需要的线条数量, 可以通过二分。
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <queue>
#include <set>
#include <stack>
using namespace std;
const int N = 5e5+10;
int main(){
long long cnt = 0, res = 0;
vector<int> p(40000);
int m = 40000;
for(int i=0; i<=m; i++){
if(i%3 == 1){
cnt += 2;
}
if(i%3 == 2){
cnt += 2;
}
res += cnt;
p[i] = res;
}
int t;
cin>>t;
while(t--){
int n;
cin>>n;
cout<<lower_bound(p.begin(), p.end(), n)-p.begin()+1<<endl;
}
return 0;
}
总结:
思维题,伤啊😢