A. Ilya and a Colorful Walk
#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 3e5 + 10;
int a[N];
int main()
{
#ifdef LOCAL
//freopen("C:/input.txt", "r", stdin);
#endif
int n, ans = 0;
cin >> n;
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
for (int i = 2; i <= n; ++i)
if (a[i] != a[1])
ans = i - 1;
for (int i = n; i >= 2; --i)
if (a[i] != a[n])
ans = max(ans, n - i);
cout << ans << endl;
return 0;
}
B. Alyona and a Narrow Fridge <二分> <贪心>
二分答案求解,每次二分一个能填装的数量m。
贪心思路,按照顺序将前m个瓶子装入vector并排序,每次将高度最相近的两个装在同一层,则当前层所需高度为max(v[i], v[i + 1]),如果最终答案小于等于限制高度则可行尝试增大m。
#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e3 + 10;
int a[N];
ll n, h;
bool check(int m)
{
vector<int> v;
for (int i = 1; i <= m; ++i)
v.push_back(a[i]);
sort(v.begin(), v.end(), greater<int>());
ll hh = h;
for (int i = 0; i < v.size(); i += 2)
hh -= v[i];
return hh >= 0;
}
int main()
{
#ifdef LOCAL
//freopen("C:/input.txt", "r", stdin);
#endif
cin >> n >> h;
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
int l = 0, r = n, ans = 0;
while (l <= r)
{
int m = l + r >> 1;
if (check(m))
l = m + 1, ans = m;
else
r = m - 1;
}
cout << ans << endl;
return 0;
}
C. Ramesses and Corner Inversion <思维> <构造>
直接将A矩阵和B矩阵进行异或,得到矩阵C,矩阵C某个位置为1则表示之前AB矩阵不相同,即如果能将C矩阵全变为0则可以将AB变换为相同。
如果C矩阵同一行内1个数为奇数则一定无法将当前行的1全部清除,如果为偶数则定能。并且会给下面某行造成偶数个影响(1个数+2、-2、0),所以不会影响下一行。
所以只需要将当前行两个1和下一行相邻的位置进行反转即可,一行一行反转下去如果最后全为0则为YES否则NO。
#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 510;
int g[N][N];
int main()
{
#ifdef LOCAL
freopen("C:/input.txt", "r", stdin);
#endif
int n, m, x;
cin >> n >> m;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
scanf("%d", &g[i][j]);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
{
scanf("%d", &x);
g[i][j] ^= x;
}
for (int i = 1; i < n; ++i)
{
for (int j = 1; j <= m; ++j)
if (g[i][j])
for (int k = j + 1; k <= m; ++k)
if (g[i][k])
{
g[i][j] ^= 1;
g[i][k] ^= 1;
g[i + 1][j] ^= 1;
g[i + 1][k] ^= 1;
break;
}
}
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
if (g[i][j])
cout << "No" << endl, exit(0);
cout << "Yes" << endl;
return 0;
}
D. Frets On Fire <思维> <二分>
因为每行增长速度相同,所以对于每个查询区间[l, r]可以转换为[0, r-l+1]而不影响答案。
将行按照第一个位置进行排序,不影响答案。排序后对于每个行i最大能造成的贡献则为s[i+1]-s[i],因为超过s[i+1]则后面都会被下一行包含,所以每行的贡献则为min(s[i + 1] - s[i], r - l + 1),最后一行的贡献只受r - l + 1影响。
两两做差,按照差值排序,并且从前向后做前缀和。对于每个查询找到第一个大于r - l + 1的位置k,在k之前的则收到自身与前面距离影响,使用前缀和计算。后k到n个受r - l + 1限制,直接区间长度*个数求和即可。
#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e5 + 10;
ll a[N], s[N];
int main()
{
#ifdef LOCAL
freopen("C:/input.txt", "r", stdin);
#endif
int n;
cin >> n;
for (int i = 1; i <= n; ++i)
scanf("%I64d", &a[i]);
sort(a + 1, a + n + 1);
for (int i = 1; i < n; ++i)
a[i] = a[i + 1] - a[i]; //当前位置的最大贡献
a[n] = LINF; //最后位置为无穷大
sort(a + 1, a + n + 1); //将贡献排序
for (int i = 1; i <= n; ++i)
s[i] = s[i - 1] + a[i]; //前缀和
int q;
cin >> q;
while (q--)
{
ll l, r;
scanf("%I64d%I64d", &l, &r);
ll m = r - l + 1; //查询长度
int k = upper_bound(a + 1, a + n + 1, m) - a; //k以前的都可以达到最大贡献
ll res = s[k - 1] + (n - k + 1) * m; //k和以后的数量*m
printf("%I64d\n", res);
}
return 0;
}
E. Pavel and Triangles <贪心>
由于木棒长度为2的次幂,所以只能3个相同的组成三角形或者2个大的1个小的组成三角形。
贪心策略,优先匹配剩余的小的木棒,然后尝试三个相同的一组,最后剩下的再加进剩余的里面。
#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 3e5 + 10;
ll a[N];
int main()
{
#ifdef LOCAL
//freopen("C:/input.txt", "r", stdin);
#endif
int n;
cin >> n;
for (int i = 1; i <= n; ++i)
scanf("%I64d", &a[i]);
ll ans = 0, s = 0, k = 0; //k剩下的单个的
for (int i = 1; i <= n; ++i)
{
int p = min(k, a[i] / 2); //优先匹配剩余
ans += p;
a[i] -= p * 2; //扣除对应数量
k -= p;
ans += a[i] / 3; //剩余的三个匹配
k += a[i] % 3; //把最后加进剩余
}
cout << ans << endl;
return 0;
}