A
暴力记录最多能形成多少对
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000 + 5;
int a[maxn];
int main()
{
ios::sync_with_stdio(false); cin.tie(0);
int n, k; cin >> n >> k;
for (int i = 0; i < n; ++i) {
int x; cin >> x;
a[x]++;
}
int cnt = 0;
for (int i = 1; i <= k; ++i) {
cnt += a[i] / 2;
if (a[i] & 1) cnt++;
}
cout << n - max(0, cnt - (n + 1) / 2) << endl;
}
B
假设吃掉x次,放入y次,则x+y=n。根据关系建立方程:(y+1)*y/2-x=k,其中y=n-x
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n, k;
ll check(ll x) {
ll tmp = (n - x + 1) * (n - x) / 2 - x - k;
return tmp;
}
int main()
{
cin >> n >> k;
ll l = 0, r = n + 1;
while (l < r) {
ll mid = l + (r - l) / 2;
ll res = check(mid);
if (res == 0) {
cout << mid << endl;
return 0;
}
else if (res > 0) l = mid + 1;
else r = mid;
}
}
C
以每一列做分析,只能从上列的状态转移,很容易dp
dp[i][0]表示该列不选择,dp[i][1]表示选择第一行的人,dp[i][2]表示选择第二的人
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
typedef long long ll;
ll line1[maxn], line2[maxn];
ll dp[maxn][5];
int main()
{
ios::sync_with_stdio(false); cin.tie(0);
int n; cin >> n;
for (int i = 1; i <= n; ++i) cin >> line1[i];
for (int i = 1; i <= n; ++i) cin >> line2[i];
for (int i = 1; i <= n; ++i) {
dp[i][0] = max(dp[i - 1][0], max(dp[i - 1][1], dp[i - 1][2]));
dp[i][1] = max(dp[i - 1][0], dp[i - 1][2]) + line1[i];
dp[i][2] = max(dp[i - 1][0], dp[i - 1][1]) + line2[i];
}
cout << max(dp[n][0], max(dp[n][1], dp[n][2])) << endl;
}
D1
分析发现每个数只会形成两种状态,且每种状态都会与每个数的另一个状态相加。计算每个数的两个状态值相加乘n即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
int main()
{
ios::sync_with_stdio(false); cin.tie(0);
int n; cin >> n;
ll ans = 0;
stack<int> ps;
for (int i = 0; i < n; ++i) {
ll x; cin >> x;
while (x) {
ps.push(x % 10);
x /= 10;
}
ll tmp = 0;
while (!ps.empty()) {
tmp = (tmp * 100 % mod + ps.top()) % mod; ps.pop();
}
ans = (ans + tmp) % mod;
ans = (ans + tmp * 10 % mod) % mod;
}
ans = ans * n % mod;
cout << ans << endl;
}
D2
两个数位数不同处理方式不同,位数不同时需要多的数直接放在前面,不需要空0。发现数据1e9,最多10位。暴力算每个数在与1-10不同位数的数计算时的两种表示的值(先放在后面和后放在后面),贡献为该位数的数量。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
const int maxn = 1e5 + 5;
ll a[maxn][13];
int cnt[13];
int get_digit(ll x) {
int res = 0;
while (x) {
x /= 10; res++;
}
return res;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0);
int n; cin >> n;
for (int i = 0; i < n; ++i) {
ll x; cin >> x;
int d = get_digit(x);
a[cnt[d]++][d] = x;
}
ll ans = 0;
for (int i = 1; i <= 10; ++i) {
for (int j = 1; j <= 10; ++j) {
for (int k = 0; k < cnt[i]; ++k) {
ll base = 1, tmp = a[k][i], y = j, sum = 0;
while (tmp) {
sum += base * (tmp % 10) % mod;
sum %= mod;
if (y > 0) base *= 100;
else base *= 10;
base %= mod;
tmp /= 10;
y--;
}
base = 10; tmp = a[k][i]; y = j - 1;
while (tmp) {
sum += base * (tmp % 10) % mod;
sum %= mod;
if (y > 0) base *= 100;
else base *= 10;
base %= mod;
tmp /= 10;
y--;
}
sum *= cnt[j];
sum %= mod;
ans += sum;
ans %= mod;
}
}
}
cout << ans << endl;
}
E
对于固定矩阵的大小,可以先预处理出每一行相邻B个元素的最小值,然后按列处理每A个元素的最小值即为矩阵大小为A*B的最小值。计算最小值可以用单调队列
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3000 + 5;
ll a[maxn][maxn], g[maxn * maxn];
int main()
{
ios::sync_with_stdio(false); cin.tie(0);
int n, m, A, B; cin >> n >> m >> A >> B;
int x, y, z; cin >> g[0] >> x >> y >> z;
for (int i = 1; i <= n * m; ++i) g[i] = (g[i - 1] * x + y) % z;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j) a[i][j] = g[(i - 1) * m + j - 1];
deque< pair<ll, int> >q;
for (int i = 1; i <= n; ++i) {
q.clear();
for (int j = 1; j <= m; ++j) {
while (!q.empty() && q.back().first >= a[i][j]) q.pop_back();
while (!q.empty() && q.front().second < j - B + 1) q.pop_front();
q.push_back(make_pair(a[i][j], j));
a[i][j] = q.front().first;
}
}
ll ans = 0;
for (int j = B; j <= m; ++j) {
q.clear();
for (int i = 1; i <= n; ++i) {
while (!q.empty() && q.back().first >= a[i][j]) q.pop_back();
while (!q.empty() && q.front().second < i - A + 1) q.pop_front();
q.push_back(make_pair(a[i][j], i));
if (i >= A) ans += q.front().first;
}
}
cout << ans << endl;
}