A 苏醒,浮出梦乡
定义 \(s_n^m\) 为 \(\{a_n\}\) 的 \(m\) 阶前缀和数组第 \(n\) 位上的值
显然 \(s_n^m = s_{n - 1}^m + s_n^{m - 1}\)
自然的,我们可以朴素的进行DP算出 \(s_n^m\) 的最大可能值
然而计算一下复杂度却发现是 \(n^2\),显然会TLE,不优化的话还会MLE
但是根据输入,易得需要预处理并且 \(O(1)\) 查询的
根据上面的状态转移方程,不难看出,\(s_n^m\) 其实就是 组合数,那么我们预处理阶乘和阶乘的逆元之后,根据组合数公式就可以 \(O(1)\) 算出 \(s_n^m\) 的值了 (预处理阶乘的复杂度是 \(O(n)\))
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr ll mod = 1e9 + 7;
// constexpr int inf = 0x3f3f3f3f;
constexpr ll inf = 0x3f3f3f3f3f3f3f3f;
constexpr ll maxn = 1000000;
ll fact[maxn + 2];
ll inv[maxn + 2];
auto power(ll a , ll b) {
ll res = 1;
while (b) {
if (b & 1) {
res = res * a % mod;
}
a = a * a % mod;
b >>= 1;
}
return res;
}
void initfact() {
fact[0] = 1;
for (ll i = 1; i <= maxn; ++ i) {
fact[i] = fact[i - 1] * i % mod;
}
inv[maxn] = power(fact[maxn], mod - 2);
for (ll i = maxn - 1; i >= 1; -- i) {
inv[i] = inv[i + 1] * (i + 1ll) % mod;
}
}
ll C(int n, int m) {
if (m > n) {
return 0;
} else if (m == 0) {
return 1;
} else {
return fact[n] * inv[m] % mod * inv[n - m] % mod;
}
}
ll f(int x, int y) {
return C(x + y - 1, y - 1);
}
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
initfact();
int tt = 1;
cin >> tt;
while (tt--) {
int n, m, d = 0;
cin >> n >> m;
cout << f(m, n) << "\n";
}
}
B 落雪,浸黑国土
不妨设整个数组的和为 \(s\)
注意到第 \(i\) 种操作可以转化为,对 \(s\) 加或者减 \(i * b_i\)
根据裴蜀定理:
\[\sum\limits_{i = 1}^{n} a_{i} x_{i} = gcd( \{ x_{i} \vert i \in [1 , n] \} ) (a_{i} \in Z) \]易得
\( ans = \begin{cases} 1, ~~~ q ~ \% ~ gcd( \{ i * b_{i} \vert i \in [1 , n] \} ) == 0 \\ 0, ~~~ q ~ \% ~ gcd( \{ i * b_{i} \vert i \in [1 , n] \} ) != 0 \\ \end{cases} \)
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int tt = 1;
cin >> tt;
while (tt--) {
int n;
cin >> n;
vector<ll> a(n + 1);
for (ll i = 1; i <= n; ++ i) {
ll x;
cin >> x;
a[i] = x * i;
}
ll g = a[1];
for (int i = 2; i <= n; ++ i) {
g = gcd(g, a[i]);
}
ll q;
cin >> q;
if (g == 0) {
if (q == 0) {
cout << "Yes\n";
} else {
cout << "No\n";
}
} else {
if (q % g == 0) {
cout << "Yes\n";
} else {
cout << "No\n";
}
}
}
}
C 相逢,总是离别
首先,进行分讨
- 当图本来不是传递的
我们只需要计算出当前所有的连通块变成传递的需要多少条边,再减去 \(m\) 即可 - 当图本来是传递的
我们只需要把最小的两个联通块合并成一个,计算需要添加的边即可
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
class DSU {
public:
int n;
vector<int> dsu, dsus;
DSU() {}
DSU(int n) { init(n); }
void init(int n) {
this -> n = n;
dsu.resize(n + 1);
dsus.resize(n + 1, 1);
iota(dsu.begin(), dsu.end(), 0);
}
int find(int a) {
if (a == dsu[a]) {
return a;
} else {
dsu[a] = find(dsu[a]);
return dsu[a];
}
}
void merge(int a, int b) {
int x = find(a);
int y = find(b);
if (x != y) {
if (dsus[x] < dsus[y]) {
swap(x, y);
}
dsu[y] = x;
dsus[x] += dsus[y];
}
}
void reboot() {
for (int i = 1; i <= n; ++ i) {
int fa = find(dsu[i]);
dsu[i] = fa;
dsus[i] = dsus[fa];
}
}
};
ll f(ll x) { return x * (x - 1ll) / 2ll; }
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int n, m;
cin >> n >> m;
DSU a(n);
a.init(n);
for (int i = 1; i <= m; ++ i) {
int u, v;
cin >> u >> v;
a.merge(u, v);
}
a.reboot();
priority_queue<ll, vector<ll>, greater<ll>> q; // 升序
set<int> st;
for (int i = 1; i <= n; ++ i) {
int fa = a.dsu[i];
if (!st.count(fa)) {
st.insert(fa);
q.push(a.dsus[fa]);
}
}
ll ans = -m, s = 0, d = 0;
int len = q.size();
for (int i = 1; i <= len; ++ i) {
ll x = q.top();
q.pop();
ans += f(x);
if (i <= 2) {
s += x;
d -= f(x);
}
}
if (ans == 0) ans += f(s) + d;
cout << ans << "\n";
}
D 人心,向背无常
这是一题有向图博弈
根据题目给的条件,可以建一颗树
显然,树的叶子结点的 \(SG\) 值为 0 (我们定义0为必胜态)
由于:
\[SG(x) = mex(\{SG(y) \vert y \in adj[x] \}) \]我们深度优先搜索时求一下每个节点的 \(SG\) 值,最后判断 \((1, 1)\) 的 \(SG\) 值是否是 \(0\) 即可
根据题目的状态转移,不难看出满足 无后效性,即可以倒着直接根据关系进行DP
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int mex(set<int> st) {
int res = 0;
for (auto x : st) {
if (x >= 0) {
if (res == x) {
res ++;
} else {
return res;
}
}
}
return res;
}
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int tt = 1;
cin >> tt;
while (tt--) {
int n, m;
cin >> n >> m;
vector<vector<int>> a(n + 1, vector<int>(m + 1, 7));
vector<vector<int>> sg(n + 2, vector<int>(m + 2, -1));
for (int i = 1; i <= n; ++ i) {
for (int j = 1; j <= m; ++ j) {
cin >> a[i][j];
}
}
for (int i = n; i >= 1; -- i) {
for (int j = m; j >= 1; -- j) {
set<int> st;
if ((a[i][j] >> 0) & 1) st.insert(sg[i + 1][j]);
if ((a[i][j] >> 1) & 1) st.insert(sg[i][j + 1]);
if ((a[i][j] >> 2) & 1) st.insert(sg[i + 1][j + 1]);
sg[i][j] = mex(st);
}
}
if (sg[1][1] == 0) {
cout << "Yes\n";
} else {
cout << "No\n";
}
}
}
https://www.acwing.com/blog/content/13279/
E 厄运,等候已久
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr ll mod = 1e9 + 7;
constexpr ll inf = 0x3f3f3f3f3f3f3f3f;
constexpr ll maxn = 1000000;
ll power(ll a, ll b) {
ll res = 1;
while (b) {
if (b & 1) {
res = res * a % mod;
}
a = a * a % mod;
b >>= 1;
}
return res;
}
ll fact[maxn + 2];
ll inv[maxn + 2];
void initfact() {
fact[0] = 1;
for (ll i = 1; i <= maxn; ++ i) {
fact[i] = fact[i - 1] * i % mod;
}
inv[maxn] = power(fact[maxn], mod - 2);
for (ll i = maxn - 1; i >= 1; -- i) {
inv[i] = inv[i + 1] * (i + 1ll) % mod;
}
}
ll C(int n, int m) {
if (m > n) {
return 0;
} else if (m == 0) {
return 1;
} else {
return fact[n] * inv[m] % mod * inv[n - m] % mod;
}
}
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
initfact();
int tt = 1;
cin >> tt;
while (tt--) {
ll n, m;
cin >> n >> m;
ll last = n - m * 5;
ll t = last / 2ll * 5ll;
if (t >= m) {
ll ans = 0;
ll P = 5ll * power(100, mod - 2) % mod;
ll Q = 95ll * power(100, mod - 2) % mod;
ll p = 1, q = power(Q, t);
for (int k = 0; k < m; ++ k) {
ans += C(t, k) * p * q;
ans %= mod;
p *= P;
q *= Q;
}
ans = mod + 1 - ans;
ans %= mod;
cout << ans << "\n";
} else {
cout << 0 << "\n";
}
}
}
F 战场,蔓延不止
对于每一个曼哈顿圆,只要起点到终点的欧几里得距离小于等于,圆心到终点的曼哈顿距离,就能不被追上
自证不难。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
const ll pi = acos(-1);
const ll E = exp(1);
constexpr ll mod = 1e9 + 7;
// constexpr int inf = 0x3f3f3f3f;
constexpr ll inf = 0x3f3f3f3f3f3f3f3f;
class Point {
public:
ll x = 0, y = 0;
Point () {}
Point (ll x, ll y) : x(x), y(y) {}
Point operator-(const Point &P) const { return Point(x - P.x, y - P.y); }
ll operator&(const Point &P) const { return x * P.x + y * P.y; } // 点积 |A||B|cosθ
friend istream &operator>>(istream &is, Point &rhs) { return is >> rhs.x >> rhs.y; }
friend ostream &operator<<(ostream &os, const Point &rhs) { return os << '(' << rhs.x << ',' << rhs.y << ')'; }
};
const Point O = {0, 0}; // 原点
ll Len2(const Point &A) { return A & A; } // 向量A长度的平方
ll Distance2(const Point &A, const Point &B) { return Len2(A - B); } // 两点间距离
ll ManhattanDistance2(const Point &A, const Point &B) { return (abs(A.x - B.x) + abs(A.y - B.y)) * (abs(A.x - B.x) + abs(A.y - B.y)); } // 两点间曼哈顿距离
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int tt = 1;
cin >> tt;
while (tt--) {
bool flag = 1;
int n;
cin >> n;
vector<Point> pl(n + 1);
for (int i = 1; i <= n; ++i) {
cin >> pl[i];
}
Point ps, pt;
cin >> ps >> pt;
ll d2 = Distance2(pt, ps);
for (int i = 1; i <= n; ++i) {
ll cur2 = ManhattanDistance2(pt, pl[i]);
if (cur2 <= d2) {
flag = 0;
break;
}
}
if (flag) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}
}
G 意志,片缕幻影
根据 \(y = lowbit(x) = ((-x) \& x)\)
可知,题目就是求 \(lowbit(x)\)
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
cout.tie(nullptr)->sync_with_stdio(false);
int tt = 1;
cin >> tt;
while (tt--) {
string s, ans = "";
cin >> s;
int len = s.size();
for (int i = len - 1; i >= 0; -- i) {
ans += s[i];
if (s[i] == '1') break;
}
reverse(ans.begin(), ans.end());
cout << ans << "\n";
}
}
/**
* title: b2.cpp
* author: Proaes Meluam
* created: 2024-11-19 19:46:54
**/
#include <bits/stdc++.h>
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
using namespace std;
using ll = long long;
using ull = unsigned long long;
const double pi = acos(-1);
const double E = exp(1);
constexpr ll mod = 1e9 + 7;
// constexpr int inf = 0x3f3f3f3f;
constexpr ll inf = 0x3f3f3f3f3f3f3f3f;
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int tt = 1;
cin >> tt;
while (tt--) {
string s;
cin >> s;
int len = s.size();
vector<int> a(len);
for (int i = 0; i < len; ++ i) {
a[i] = s[i] - '0';
}
reverse(a.begin(), a.end());
vector<int> b = a;
for (int i = 0; i < len; ++ i) {
a[i] ^= 1;
}
a[0]++;
int carry = 0;
for (int i = 0; i < len; ++ i) {
carry += a[i];
a[i] = carry % 2;
carry /= 2;
}
vector<int> ans(len);
for (int i = 0; i < len; ++ i) {
ans[i] = a[i] & b[i];
}
reverse(ans.begin(), ans.end());
int be = 0;
for (int i = 0; i < len; ++ i) {
if (ans[i] == 1) be = i;
}
string sans = "";
for (int i = be; i < len; ++ i) {
char c = ans[i] + '0';
sans += c;
}
cout << sans << "\n";
}
}
H 失语,产自多言
#include <bits/stdc++.h>
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
using namespace std;
using ll = long long;
constexpr ll inf = 0x3f3f3f3f3f3f3f3f;
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int tt = 1;
cin >> tt;
while (tt--) {
int n;
cin >> n;
vector<ll> v(n + 1);
vector<ll> dp(n + 1, inf);
for (int i = 1; i <= n; ++ i) cin >> v[i];
if (n == 1) {
cout << v[n] << "\n";
} else {
vector<int> f(n + 1); // f[i] 存 i 的最大因子
for (int k = 1; k <= n; ++ k) {
for (int i = k + k; i <= n; i += k) {
f[i] = max(f[i], k);
}
}
vector<vector<ll>> adj(n + 1, vector<ll>());
for (int i = 2; i <= n; ++ i) {
adj[f[i]].emplace_back(i);
}
for (int i = 1; i <= n; ++ i) {
// 预处理,把叶子结点存进dp数组,显然叶子节点只能减,存进后就是当前节点的最大值
if ((int)adj[i].size() == 0) {
dp[i] = v[i];
}
}
auto transition = [&](int child, int father) {
if (dp[child] > v[father]) {
dp[father] = min(dp[father], (v[father] + dp[child]) / 2ll);
} else {
dp[father] = min(dp[father], dp[child]);
}
};
auto dfs = [&](auto self , int cur , int father) -> void {
for (auto child : adj[cur]) {
if (child == father) continue; // 防止往回遍历
self(self, child, cur);
if (cur != 1) { // 特判根节点,因为根节点只能无需保证小于等于他的子树
transition(child, cur);
}
}
};
dfs(dfs, 1, 0);
// 特判根节点,此时特别的,dp[1]表示的不是节点1的最大值,而是节点1的最大增加值,所以最后要加上v[1]
for (auto child : adj[1]) {
dp[1] = min(dp[1], dp[child]);
}
// debug(dp);
// 当dp[1]没有增加时,要把dp[1]置 0
if (dp[1] == inf) dp[1] = 0;
// 由于dp[1]表示的不是节点1的最大值,而是节点1的最大增加值,所以最后要加上w[1]
ll ans = dp[1] + v[1];
cout << ans << "\n";
}
}
}
标签:ZZJC,int,题解,ll,cin,long,组队,tt,mod From: https://www.cnblogs.com/Proaes/p/18568751