A - Min Or Sum
根据题目要求可以发现,要使得总和尽可能地小,应尽可能将选择的 ( a i , a j ) (a_i, a_j) (ai,aj)变为 ( a i ∣ a j , 0 ) (a_i | a_j, 0) (ai∣aj,0)。那么统计 1 1 1的位数求和或直接所有元素求或即可。
#include <bits/stdc++.h>
#define int long long
inline void solve(){
int ans = 0, n = 0; std::cin >> n;
for(int i = 1; i <= n; i++){
int x; std::cin >> x;
ans |= x;
}
std::cout << ans << std::endl;
}
signed main(){
int t = 0; std::cin >> t;
while(t--) solve();
return 0;
}
B - Avoid Local Maximums
扫描序列,每当发现一个local minium
就将其替换为两侧数字较大的一个(或者直接按照单增贪心修改)。这样可以保证单向单调性。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 10;
int a[N], book[N];
inline void solve(){
int n = 0, cnt = 0; cin >> n;
memset(book, 0, sizeof book);
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 2; i < n; i++){
if(a[i] > a[i - 1] && a[i] > a[i + 1]){
a[i] = max(a[i + 1], a[i + 2]);
cnt++;
}
}
cout << cnt << endl;
for(int i = 1; i <= n; i++){
cout << a[i] << ' ';
}
cout << endl;
}
signed main(){
int t = 0; cin >> t;
while(t--) solve();
return 0;
}
C - Differential Sorting
每次可以选择 1 ≤ x ≤ y ≤ z ≤ n 1 \leq x \leq y \leq z \leq n 1≤x≤y≤z≤n,然后令 a x = a y − a z a_x = a_y - a_z ax=ay−az。通过有限次操作令序列有序(不递减)。
首先考虑非法情况:
- 如果 a n − 1 ≥ a n a_{n - 1} \geq a_n an−1≥an,那么无法将 a n − 1 a_{n - 1} an−1元素修改为更小的元素,此时非法
- 如果 a n < 0 a_n < 0 an<0,如果序列未排序,那么为了将序列修改为不递减,我们应该将整个序列修改为 a n − 1 − a n a_{n - 1} - a_n an−1−an。此时由于 a n < 0 a_n < 0 an<0,那么无法满足不递减的条件。
判读非法情况,然后输出即可。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 4e5 + 10;
int a[N];
inline void solve(){
int n = 0; cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
if(is_sorted(a + 1, a + 1 + n)) cout << 0 << endl;
else if(a[n] < a[n - 1] || a[n] < 0) puts("-1");
else{
cout << n - 2 << endl;
for(int i = 1; i <= n - 2; i++) cout << i << ' ' << n - 1 << ' ' << n << endl;
}
}
signed main(){
int t = 0; cin >> t;
while(t--) solve();
return 0;
}
D - Infinite Set
构造集合 S S S,使满足任一条件:
- x ∈ S , x ∈ a i x \in S, x \in {a_i} x∈S,x∈ai
- x ∈ S , y = 2 x + 1 ∈ S x \in S, y = 2x + 1 \in S x∈S,y=2x+1∈S
- x ∈ s , y = 4 x ∈ S x \in s, y = 4x \in S x∈s,y=4x∈S
求集合中小于 2 p 2^p 2p的元素的个数。
首先考虑 a a a序列只有一个元素的情况:
y = 2 x + 1 y = 2x + 1 y=2x+1和 y = 4 x y = 4x y=4x有很明显的区别:前者是左移 1 1 1位 + 1 +1 +1,后者是左移两位。每次可以生成两个数字。我们反过来考虑,一个数字可以由两种情况转移而来:设数字的长度为 l l l,则长度为 l − 1 l - 1 l−1和长度 l − 2 l - 2 l−2的两个可以转移得到。
如果推广到多个元素的状态,那么只需要预处理出各个起始长度的值(这里需要去重),然后计数即可。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 10, MOD = 1e9 + 7;
int a[N], dp[N];
set<int> st;
inline void solve(){
st.clear();
int n = 0, ans = 0, p = 0; cin >> n >> p;
for(int i = 1; i <= n; i++) cin >> a[i];
auto countx = [&](int x, int ans = 0){ while((1 << ans) <= x) ans++; return ans; };
sort(a + 1, a + 1 + n);
for(int i = 1; i <= n; i++){
int x = a[i];
//找到最初的数并判重
while(x != 1){
if(st.count(x)) break;
if(x % 4 == 0) x >>= 2;
else if(x & 1) x >>= 1;
else break;
}
if(st.count(x)) continue;
st.insert(a[i]);
dp[countx(a[i])]++;
}
for(int i = 2; i <= p; i++) dp[i] = (dp[i] + dp[i - 1] + dp[i - 2]) % MOD;
for(int i = 1; i <= p; i++) (ans += dp[i]) %= MOD;
cout << ans << endl;
}
signed main(){
//int t = 0; cin >> t;
//while(t--)
solve();
return 0;
}