A – 礼物
sb 暴力出奇迹,欺骗人的感情。
敢情您特么\(1e9\)的复杂度都能过?真的服气。
// A.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1010;
int prefix[MAX_N][MAX_N], suffix[MAX_N][MAX_N];
int n, ai[MAX_N], bi[MAX_N], ci[MAX_N], m;
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d%d%d", &ai[i], &bi[i], &ci[i]);
for (int i = 1; i <= n; i++)
for (int j = 0; j < MAX_N; j++)
{
prefix[i][j] = prefix[i - 1][j];
if (j >= ai[i])
prefix[i][j] = max(prefix[i][j], prefix[i - 1][j - ai[i]] + bi[i]);
}
for (int i = n; i >= 1; i--)
for (int j = 0; j < MAX_N; j++)
{
suffix[i][j] = suffix[i + 1][j];
if (j >= ai[i])
suffix[i][j] = max(suffix[i][j], suffix[i + 1][j - ai[i]] + bi[i]);
}
scanf("%d", &m);
while (m--)
{
int del, money;
scanf("%d%d", &del, &money), del++;
int ans = 0;
for (int i = 0; i <= money; i++)
ans = max(ans, prefix[del - 1][i] + suffix[del + 1][money - i]);
printf("%d\n", ans);
}
return 0;
}
// A.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1010;
int prefix[MAX_N][MAX_N], suffix[MAX_N][MAX_N];
int n, ai[MAX_N], bi[MAX_N], ci[MAX_N], m;
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d%d%d", &ai[i], &bi[i], &ci[i]);
for (int i = 1; i <= n; i++)
for (int j = 0; j < MAX_N; j++)
{
prefix[i][j] = prefix[i - 1][j];
if (j >= ai[i])
prefix[i][j] = max(prefix[i][j], prefix[i - 1][j - ai[i]] + bi[i]);
}
for (int i = n; i >= 1; i--)
for (int j = 0; j < MAX_N; j++)
{
suffix[i][j] = suffix[i + 1][j];
if (j >= ai[i])
suffix[i][j] = max(suffix[i][j], suffix[i + 1][j - ai[i]] + bi[i]);
}
scanf("%d", &m);
while (m--)
{
int del, money;
scanf("%d%d", &del, &money), del++;
int ans = 0;
for (int i = 0; i <= money; i++)
ans = max(ans, prefix[del - 1][i] + suffix[del + 1][money - i]);
printf("%d\n", ans);
}
return 0;
}
// A.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 1010; int prefix[MAX_N][MAX_N], suffix[MAX_N][MAX_N]; int n, ai[MAX_N], bi[MAX_N], ci[MAX_N], m; int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d%d%d", &ai[i], &bi[i], &ci[i]); for (int i = 1; i <= n; i++) for (int j = 0; j < MAX_N; j++) { prefix[i][j] = prefix[i - 1][j]; if (j >= ai[i]) prefix[i][j] = max(prefix[i][j], prefix[i - 1][j - ai[i]] + bi[i]); } for (int i = n; i >= 1; i--) for (int j = 0; j < MAX_N; j++) { suffix[i][j] = suffix[i + 1][j]; if (j >= ai[i]) suffix[i][j] = max(suffix[i][j], suffix[i + 1][j - ai[i]] + bi[i]); } scanf("%d", &m); while (m--) { int del, money; scanf("%d%d", &del, &money), del++; int ans = 0; for (int i = 0; i <= money; i++) ans = max(ans, prefix[del - 1][i] + suffix[del + 1][money - i]); printf("%d\n", ans); } return 0; }
B – 异或
这道题太特么傻逼了。
考虑一个位有可能作为答案的贡献,当且仅当之前的位都相等。在 Trie 树上,任意一个节点都可以保证前缀相等,所以每一个节点的贡献就是\(2^{len} \times son_0 \times son_1\)。
// B.cpp
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX_N = 1e5 + 200;
const ll mod = 199907210507;
struct node
{
int ch[2];
ll val;
} nodes[MAX_N * 70];
ll ptot = 1, n, arr[MAX_N], ans, pow2[70];
void insert(ll x)
{
int p = 1;
for (int i = 0; i <= 62; i++)
{
int bit = (x >> i) & 1;
if (nodes[p].ch[bit] == 0)
nodes[p].ch[bit] = ++ptot;
nodes[p].val++, p = nodes[p].ch[bit];
}
}
void dfs(int u, int cnt)
{
if (u == 0)
return;
(ans += 1LL * nodes[nodes[u].ch[0]].val * nodes[nodes[u].ch[1]].val % mod * pow2[cnt]) %= mod;
dfs(nodes[u].ch[0], cnt + 1), dfs(nodes[u].ch[1], cnt + 1);
}
int main()
{
scanf("%lld", &n);
for (int i = pow2[0] = 1; i < 70; i++)
pow2[i] = 1LL * pow2[i - 1] * 2 % mod;
for (int i = 1; i <= n; i++)
scanf("%lld", &arr[i]), insert(arr[i]);
dfs(1, 0), printf("%lld", 1LL * ans * 2 % mod);
return 0;
}
// B.cpp
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX_N = 1e5 + 200;
const ll mod = 199907210507;
struct node
{
int ch[2];
ll val;
} nodes[MAX_N * 70];
ll ptot = 1, n, arr[MAX_N], ans, pow2[70];
void insert(ll x)
{
int p = 1;
for (int i = 0; i <= 62; i++)
{
int bit = (x >> i) & 1;
if (nodes[p].ch[bit] == 0)
nodes[p].ch[bit] = ++ptot;
nodes[p].val++, p = nodes[p].ch[bit];
}
}
void dfs(int u, int cnt)
{
if (u == 0)
return;
(ans += 1LL * nodes[nodes[u].ch[0]].val * nodes[nodes[u].ch[1]].val % mod * pow2[cnt]) %= mod;
dfs(nodes[u].ch[0], cnt + 1), dfs(nodes[u].ch[1], cnt + 1);
}
int main()
{
scanf("%lld", &n);
for (int i = pow2[0] = 1; i < 70; i++)
pow2[i] = 1LL * pow2[i - 1] * 2 % mod;
for (int i = 1; i <= n; i++)
scanf("%lld", &arr[i]), insert(arr[i]);
dfs(1, 0), printf("%lld", 1LL * ans * 2 % mod);
return 0;
}
// B.cpp #include <bits/stdc++.h> #define ll long long using namespace std; const int MAX_N = 1e5 + 200; const ll mod = 199907210507; struct node { int ch[2]; ll val; } nodes[MAX_N * 70]; ll ptot = 1, n, arr[MAX_N], ans, pow2[70]; void insert(ll x) { int p = 1; for (int i = 0; i <= 62; i++) { int bit = (x >> i) & 1; if (nodes[p].ch[bit] == 0) nodes[p].ch[bit] = ++ptot; nodes[p].val++, p = nodes[p].ch[bit]; } } void dfs(int u, int cnt) { if (u == 0) return; (ans += 1LL * nodes[nodes[u].ch[0]].val * nodes[nodes[u].ch[1]].val % mod * pow2[cnt]) %= mod; dfs(nodes[u].ch[0], cnt + 1), dfs(nodes[u].ch[1], cnt + 1); } int main() { scanf("%lld", &n); for (int i = pow2[0] = 1; i < 70; i++) pow2[i] = 1LL * pow2[i - 1] * 2 % mod; for (int i = 1; i <= n; i++) scanf("%lld", &arr[i]), insert(arr[i]); dfs(1, 0), printf("%lld", 1LL * ans * 2 % mod); return 0; }
C – 子集
非常奇妙的一道题。
答案是\(2^{n \times k}\)。我想了很久的原因来解释这个答案,也感谢 XG_Zepto 和 CrazyDave 的思考。我们可以发现,选择一种单调(非偏序的)的点集合,并往这样的集合里面填入数字即可确定整个方案。
我们指「非偏序的点」,形如图中两个 B 点的关系:
A
^
|
A <- A
^ ^
| |
A <- A <- B
^ ^ ^
| | |
A <- B <- A <- A
A
^
|
A <- A
^ ^
| |
A <- A <- B
^ ^ ^
| | |
A <- B <- A <- A
A ^ | A <- A ^ ^ | | A <- A <- B ^ ^ ^ | | | A <- B <- A <- A
定义这样的点为某个元素最早存在的点,往这样的点中放元素可以让上游的区域全部覆盖该元素。考虑有\(2^k\)个这样的点集合(也就是「非偏序的点」组成的集合的子集个数),然后每个元素放入某个集合,那么元素个数就是\(2^{nk}\)。
大概这样,我还需要再进行思考。
关于「非偏序的点」组成的集合的子集个数为\(2^k\)的证明 from XG_Zepto:
记\(f(k)\)为从第\(k\)行开始向上的非偏序点集合个数,考虑第\(k\)行包括了之前的所有情况,所以\(f(k) = 2 + \sum_{i = 1}^{k – 1} f(i)\),然后这个\(2\)代表着独占情况。
大概就是这样。
// C.cpp
#include <bits/stdc++.h>
#define ll unsigned long long
using namespace std;
const ll mod = 7528443412579576937;
ll quick_mul(ll x, ll y)
{
ll res = 0;
if (x < y)
swap(x, y);
while (y)
{
if (y & 1LL)
res = (res + x < mod) ? (res + x) : (res + x - mod);
x = (x + x < mod) ? (x + x) : (x + x - mod);
y >>= 1LL;
}
return res;
}
ll quick_pow(ll bas, ll tim)
{
ll ans = 1;
while (tim)
{
if (tim & 1LL)
ans = quick_mul(ans, bas);
bas = quick_mul(bas, bas);
tim >>= 1LL;
}
return ans;
}
int main()
{
ll n, k;
scanf("%lld%lld", &n, &k), printf("%lld", quick_pow(2, 1LL * n * k));
return 0;
}
// C.cpp
#include <bits/stdc++.h>
#define ll unsigned long long
using namespace std;
const ll mod = 7528443412579576937;
ll quick_mul(ll x, ll y)
{
ll res = 0;
if (x < y)
swap(x, y);
while (y)
{
if (y & 1LL)
res = (res + x < mod) ? (res + x) : (res + x - mod);
x = (x + x < mod) ? (x + x) : (x + x - mod);
y >>= 1LL;
}
return res;
}
ll quick_pow(ll bas, ll tim)
{
ll ans = 1;
while (tim)
{
if (tim & 1LL)
ans = quick_mul(ans, bas);
bas = quick_mul(bas, bas);
tim >>= 1LL;
}
return ans;
}
int main()
{
ll n, k;
scanf("%lld%lld", &n, &k), printf("%lld", quick_pow(2, 1LL * n * k));
return 0;
}
// C.cpp #include <bits/stdc++.h> #define ll unsigned long long using namespace std; const ll mod = 7528443412579576937; ll quick_mul(ll x, ll y) { ll res = 0; if (x < y) swap(x, y); while (y) { if (y & 1LL) res = (res + x < mod) ? (res + x) : (res + x - mod); x = (x + x < mod) ? (x + x) : (x + x - mod); y >>= 1LL; } return res; } ll quick_pow(ll bas, ll tim) { ll ans = 1; while (tim) { if (tim & 1LL) ans = quick_mul(ans, bas); bas = quick_mul(bas, bas); tim >>= 1LL; } return ans; } int main() { ll n, k; scanf("%lld%lld", &n, &k), printf("%lld", quick_pow(2, 1LL * n * k)); return 0; }