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;
}