A. Elevator or Stairs?
签.
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int x, y, z, t[3]; 5 6 int main() 7 { 8 while (scanf("%d%d%d", &x, &y, &z) != EOF) 9 { 10 for (int i = 0; i < 3; ++i) scanf("%d", t + i); 11 int a = (abs(z - x) + abs(x - y)) * t[1] + 3 * t[2]; 12 int b = abs(x - y) * t[0]; 13 puts(a <= b ? "YES" : "NO"); 14 } 15 return 0; 16 }
B. Appending Mex
签.
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 int n, a[N], vis[N], last; 6 7 void solve() 8 { 9 for (int i = 1; i <= n; ++i) 10 { 11 while (vis[last + 1]) ++last; 12 if (a[i] > last + 1) 13 { 14 printf("%d ", i); 15 return; 16 } 17 vis[a[i]] = 1; 18 } 19 puts("-1"); 20 } 21 22 int main() 23 { 24 while (scanf("%d", &n) != EOF) 25 { 26 memset(vis, 0, sizeof vis); last = -1; 27 for (int i = 1; i <= n; ++i) scanf("%d", a + i); 28 solve(); 29 } 30 return 0; 31 }
C. Candies Distribution
Upsolved.
题意:
一个序列,$a_i取值为[1, n]$
告诉你$每个数左边有多少数大于你,记为l_i$
$右边有多少数大于你,记为r_i$
让你还原出这个序列,如果没有合法的输出$NO$
思路:
$我们知道一个数的l_i + r_i 越大,那么这个数越小$
$那我们不妨令 a_i = n - l_i - r_i$
$再检查一遍即可$
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 1010 5 int n, l[N], r[N], v[N]; 6 7 int main() 8 { 9 while (scanf("%d", &n) != EOF) 10 { 11 for (int i = 1; i <= n; ++i) scanf("%d", l + i); 12 for (int i = 1; i <= n; ++i) scanf("%d", r + i); 13 for (int i = 1; i <= n; ++i) v[i] = n - l[i] - r[i]; 14 bool flag = true; 15 for (int i = 1; i <= n; ++i) 16 { 17 for (int j = 1; j < i; ++j) 18 if (v[j] > v[i]) 19 --l[i]; 20 for (int j = i + 1; j <= n; ++j) 21 if (v[j] > v[i]) 22 --r[i]; 23 if (l[i] != 0 || r[i] != 0) 24 { 25 flag = false; 26 break; 27 } 28 } 29 if (!flag) puts("NO"); 30 else 31 { 32 puts("YES"); 33 for (int i = 1; i <= n; ++i) 34 printf("%d%c", v[i], " "[i == n]); 35 } 36 } 37 return 0; 38 }
D. Changing Array
Upsolved.
题意:
给一个序列,$可以将每个位置上的数取反$
$求最多有多少子区间的异或和不为0$
思路:
求最多有多少子区间$异或和不为0,比较困难$
$正难则反,我们考虑反面,我们求最少有多少个子区间异或和为0$
$我们知道一段区间l, r的异或和是S_r oplus S_[l - 1]$
$S表示前缀异或$
$那么一个序列的前缀异或里面如果有x个a, 那么子区间异或为0的个数为frac{a cdot (a - 1)}{2}$
$我们考虑 b = ~a, 而且a, b之间可以互相转化,并且只能互相转化,而不能转化为其他的数字$
$令x = a的个数, y = b的个数$
$我们令n = x + y $
$那么a, b构成的子区间个数就是 frac{x cdot (x - 1)}{2} + frac{y cdot (y - 1)}{2}$
$将n = x + y 代入$
$就得到一个一元二次方程,取对称轴即可$
$我们考虑转化都是oplus (1 << k) - 1$
转化两次即相当于没有转化
$所以每个前缀异或都能转化为自己想要的那个数$
$为什么不考虑前面的数转化了会影响到后面的前缀异或?$
$那后面那个如果受影响了,再转化回来不就好了?$
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define N 200010 6 int n, k; 7 int a[N]; 8 map <int, int> mp; 9 10 int main() 11 { 12 while (scanf("%d%d", &n, &k) != EOF) 13 { 14 mp.clear(); mp[0] = 1; 15 int d = (1 << k) - 1; 16 for (int i = 1; i <= n; ++i) scanf("%d", a + i); 17 for (int i = 1; i <= n; ++i) 18 { 19 a[i] ^= a[i - 1]; 20 ++mp[a[i]]; 21 if (mp.find(a[i] ^ d) == mp.end()) mp[a[i] ^ d] = 0; 22 } 23 ll res = 0; 24 for (auto it : mp) if (it.first > (it.first ^ d)) 25 { 26 int a = it.second, n = a + mp[it.first ^ d]; 27 int b = n / 2; 28 res += (1ll * n * n + 2ll * b * b - 2ll * b * n - n) / 2; 29 } 30 printf("%lld ", 1ll * n * (n + 1) / 2 - res); 31 } 32 return 0; 33 }