A
只需判断和的大小关系即可。
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
#define endl '\n'
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<int> h(n + 1);
for (int i = 1; i <= n; ++i)
cin >> h[i];
if (h[1] < h[n])
cout << "YES" << endl;
else
cout << "NO" << endl;
return 0;
}
B
不难证明,一个数的因子个数为奇数的充要条件为这个数为完全平方数。
故答案为。
本题的数据范围比较小,暴力也可通过。
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
#define endl '\n'
void solve()
{
int n;
cin >> n;
cout << floor(sqrt(n)) << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--)
solve();
return 0;
}
C
注意到操作前后的总和不变,故能变成的一个必要条件是它们的总和相等。
然后每次找一个的和的做操作即可。
时间复杂度。
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
#define endl '\n'
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<LL> a(n), b(n);
for (int i = 0; i < n; ++i)
cin >> a[i];
for (int i = 0; i < n; ++i)
cin >> b[i];
LL s1 = accumulate(a.begin(), a.end(), 0LL);
LL s2 = accumulate(b.begin(), b.end(), 0LL);
if (s1 != s2)
{
cout << "-1" << endl;
return 0;
}
LL ans = 0;
for (int i = 0; i < n; ++i)
ans += abs(a[i] - b[i]);
cout << ans / 2 << endl;
return 0;
}
D
先考虑没有传送门的情况,显然这是一个简单的dp。
设为从到所能达到的最大值。
同时设为,从到所能达到的最大值。
这两个数组都可以计算出来,具体可以看参考代码。
对于每次询问,可以发现传送门的个数不多,故枚举使用传送门的入口和出口即可。
时间复杂度。
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
#define endl '\n'
const LL inf = 1e18;
void solve()
{
int n, m;
cin >> n >> m;
vector<vector<LL>> f(n + 10, vector<LL>(m + 10, -inf)), g(n + 10, vector<LL>(m + 10, -inf));
vector<vector<LL>> a(n + 10, vector<LL>(m + 10));
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
cin >> a[i][j];
// compute f
f[0][1] = 0;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
f[i][j] = max(f[i - 1][j], f[i][j - 1]) + a[i][j];
// compute g
g[n][m + 1] = 0;
for (int i = n; i >= 1; --i)
for (int j = m; j >= 1; --j)
g[i][j] = max(g[i + 1][j], g[i][j + 1]) + a[i][j];
int T;
cin >> T;
while (T--)
{
int k;
cin >> k;
vector<pair<int, int>> b(k);
for (int i = 0; i < k; ++i)
cin >> b[i].first >> b[i].second;
LL ans = f[n][m];
for (int i = 0; i < k; ++i)
for (int j = 0; j < k; ++j)
{
if (i == j)
continue;
int x1 = b[i].first, y1 = b[i].second;
int x2 = b[j].first, y2 = b[j].second;
ans = max(ans, f[x1][y1] + g[x2][y2]);
}
cout << ans << endl;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
solve();
return 0;
}
E
考虑二分答案。
对于每一个二分的值,我们尝试去计算小于等于的个数。
将,排序,尝试枚举,而后我们可以使用二分或者双指针来计算中小于等于中的元素。求出它们的和。
至于题目中的限制,我们可以把所有限制的权值算出后排序,然后二分查找出小于的个数,用上述的和减掉个数,就是小于等于的数的个数。
设 ,则时间复杂度为。
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
#define endl '\n'
const LL inf = 1e12 + 10;
void solve()
{
int n, m, k, Q;
cin >> n >> m >> k >> Q;
vector<LL> a(n + 1), b(m + 1);
for (int i = 1; i <= n; ++i)
cin >> a[i];
for (int i = 1; i <= m; ++i)
cin >> b[i];
vector<LL> c(k + 1);
for (int i = 1; i <= k; ++i)
{
LL x, y;
cin >> x >> y;
c[i] = a[x] * b[y];
}
sort(c.begin() + 1, c.end());
sort(a.begin() + 1, a.end());
sort(b.begin() + 1, b.end());
while (Q--)
{
LL x;
cin >> x;
auto check = [&](LL mid) -> bool
{
LL sum = 0;
for (int i = 1; i <= n; ++i)
{
LL p = upper_bound(b.begin(), b.end(), mid / a[i]) - b.begin() - 1;
sum += p;
}
sum -= upper_bound(c.begin(), c.end(), mid) - c.begin() - 1;
return (sum >= x);
};
LL l = 0, r = inf;
while (l < r)
{
LL mid = (l + r) / 2;
if (check(mid))
r = mid;
else
l = mid + 1;
}
cout << l << endl;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
solve();
return 0;
}
F
为了更好的解释问题,在这里定义一下所需的符号。
设随机变量为合法的状态,即等可能地取到所有的情况;函数为的最大间隔。
根据期望的定义,我们有
考虑怎么求,也就是的方案数。
可以发现个人会产生个间隔,设第个间隔的大小为,于是有
其中。
那么。
故对于,要有,有。
考虑容斥。设。则有
其中为容斥中第个的个数,可以通过隔板法等方法得到。
注意到只有时组合数才有意义,即。
故总的有意义的项数为。
所以时间复杂度为。
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
using i64 = long long;
#define endl '\n'
using db = double;
template <class T>
using max_heap = priority_queue<T>;
template <class T>
using min_heap = priority_queue<T, vector<T>, greater<>>;
constexpr int P = 998244353;
int norm(int x)
{
if (x < 0)
x += P;
if (x >= P)
x -= P;
return x;
}
template <class T>
T power(T a, long long b)
{
T res = 1;for (; b; b /= 2, a *= a){if (b % 2)res *= a;}return res;
}
struct Z
{
int x;
Z(int x = 0) : x(norm(x)) {}
int val() const{return x;}
Z operator-() const{return Z(norm(P - x));}
Z inv() const{assert(x != 0);return power(*this, P - 2);}
Z &operator*=(const Z &rhs){x = i64(x) * rhs.x % P;return *this;}
Z &operator+=(const Z &rhs){x = norm(x + rhs.x);return *this;}
Z &operator-=(const Z &rhs){x = norm(x - rhs.x);return *this;}
Z &operator/=(const Z &rhs){return *this *= rhs.inv();}
friend Z operator*(const Z &lhs, const Z &rhs){Z res = lhs;res *= rhs;return res;}
friend Z operator+(const Z &lhs, const Z &rhs){Z res = lhs;res += rhs;return res;}
friend Z operator-(const Z &lhs, const Z &rhs){Z res = lhs;res -= rhs;return res;}
friend Z operator/(const Z &lhs, const Z &rhs){Z res = lhs;res /= rhs;return res;}
friend std::istream &operator>>(std::istream &is, Z &a){i64 v;is >> v;a = Z(v);return is;}
friend std::ostream &operator<<(std::ostream &os, const Z &a){return os << a.val();}
};
const int N = 2e6 + 100;
vector<Z> fac(N + 1);
vector<Z> invfac(N + 1);
Z binom(int nn, int mm)
{
if (nn < mm)
return 0;
return fac[nn] * invfac[nn - mm] * invfac[mm];
};
int main()
{
fac[0] = 1;
for (int i = 1; i <= N; ++i)
fac[i] = fac[i - 1] * i;
invfac[N] = 1 / fac[N];
for (int i = N - 1; i >= 0; --i)
invfac[i] = invfac[i + 1] * (i + 1);
int n, m;
cin >> n >> m;
Z ans = 0;
Z sum = binom(m, n);
for (int d = 1; d <= m; ++d)
{
Z res = 0;
for (int i = 0; i <= n + 1; ++i)
{
LL s = d * i;
Z sgn = (i % 2) ? -1 : 1;
res += sgn * binom(n + 1, i) * binom((m + 1) - s - 1, n);
if (s > m)
break;
}
ans += (1 - res / sum);
}
cout << ans << endl;
return 0;
}
全部评论
(3) 回帖