闲话 23.2.27
闲话
所以有人觉得我这些博客不是闲话嘛?
除了那些闲话一个字没写的那种?
但其实就算那种也算是闲话了
反正只是为了写着开心嘛
不管叫啥 它的定义总归是那些东西!
今天放的是 Credit EX 确实挺好听的
感觉也不能说年龄差大的人喜欢的东西就是不一样 这样太绝对了
只能说青年的经历对喜好起着一定的作用 还是得具体情况具体分析
感觉同机房人也没几个(有吗?)和我的喜好相同的 或者说很多喜好是相异的
只能说互相包容吧
upd: 谁能拒绝白毛红瞳。
所以今天没想到推啥歌
先放放
模拟赛!
我稍后再去找题写吧(
T1 冤家路窄
开这题时想的是我肯定搞不出来(
中间还假了一阵子(
上来肯定想最短路 dag,然后我就冲了一个 dij。
憋了十分钟想到所有方案减去不合法的方案,然后我就冲了一个拓扑排序。设 \(f(s/t,u)\) 表示从 \(s/t\) 出发到 \(u\) 的路径的计数,\(dis(s/t, u)\) 表示从 \(s/t\) 出发到 \(u\) 的最短路长度。
所有方案就是 \(f(s, t) \times f(t, s)\);不合法方案的话,第一想法肯定是枚举在哪里遇到。
在某点遇到很好想,若 \(dis(s, u) = dis(t, u)\) 则方案就是 \(([s\to u]\times [u\to t]) \times ([t\to u]\times [u\to s])\),也就是 \(f(s, u)^2 \times f(t, u)^2\)。
在边遇到我想了一阵子。然后八点多才打完
若 \(dis(s, u) < dis(t, u) \ \land \ dis(s, v) > dis(t, v)\) 则会在这条边的非端点处遇到。方案就是 \(([s\to u] \times [v\to t])\times ([t\to v] \times [u\to s])\),也就是 \(f(s, u)^2 \times f(t, v)^2\)。
直接写就行了。总时间复杂度 \(O(m\log n)\)。
code
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii; typedef vector<int> vi; typedef vector<pii> vp; typedef long long ll;
#define rep(i,s,t) for (register int i = (s), i##__ = (t) + 1; i < i##__; ++ i)
#define pre(i,s,t) for (register int i = (s), i##__ = (t) - 1; i > i##__; -- i)
#define file(fl) freopen(#fl".in", "r", stdin), freopen(#fl".out", "w", stdout)
#define timer cerr << 1. * clock() / CLOCKS_PER_SEC << endl
#define iot ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define eb emplace_back
const int N = 2e5 + 10, mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll infll = 0x3f3f3f3f3f3f3f3f;
int n, m, t1, t2, t3, s, t, ind[2][N], ans;
vp gr[N];
vi fa[2][N], gs[2][N];
ll dis[2][N]; bool vis[N];
void dij(int st, int id) {
rep(i,1,n) dis[id][i] = infll, vis[i] = 0;
priority_queue<pair<ll, int> > que;
que.emplace(0, st), dis[id][st] = 0;
while (que.size()) {
int u = que.top().second; que.pop();
if (vis[u]) continue; vis[u] = 1;
for (auto ed : gr[u]) {
if (dis[id][ed.first] > dis[id][u] + ed.second) {
fa[id][ed.first].clear(); fa[id][ed.first].eb(u);
dis[id][ed.first] = dis[id][u] + ed.second;
if (!vis[ed.first]) que.emplace(- dis[id][ed.first], ed.first);
} else if (dis[id][ed.first] == dis[id][u] + ed.second)
fa[id][ed.first].eb(u);
}
}
}
int cnt[2][N];
inline int norm(int va) { return va - (va >= mod) * mod; }
void topo(int st, int id) {
queue<int> que;
cnt[id][st] = 1;
rep(i,1,n) if (ind[id][i] == 0) que.emplace(i);
while (que.size()) {
int u = que.front(); que.pop();
for (auto v : gs[id][u]) {
-- ind[id][v], cnt[id][v] = norm(cnt[id][v] + cnt[id][u]);
if (ind[id][v] == 0) que.emplace(v);
}
}
}
signed main() {
iot; file(avoid);
cin >> n >> m >> s >> t;
rep(i,1,m) {
cin >> t1 >> t2 >> t3;
gr[t1].eb(t2, t3), gr[t2].eb(t1, t3);
}
dij(s, 0), dij(t, 1);
rep(u,1,n) for (auto ft : fa[0][u]) {
gs[0][ft].eb(u), ind[0][u] ++;
gs[1][u].eb(ft), ind[1][ft] ++;
}
topo(s, 0), topo(t, 1);
ans = 1ll * cnt[0][t] * cnt[0][t] % mod;
rep(u,1,n) if (dis[0][u] == dis[1][u])
ans = (ans - 1ll * cnt[0][u] * cnt[0][u] % mod * cnt[1][u] % mod * cnt[1][u] % mod + mod) % mod;
rep(u,1,n) for (auto v : gs[0][u]) if (dis[0][u] < dis[1][u] and dis[0][v] > dis[1][v]) {
ans = (ans - 1ll * cnt[0][u] * cnt[0][u] % mod * cnt[1][v] % mod * cnt[1][v] % mod + mod) % mod;
} cout << ans << '\n';
}
T2 夹克姥爷 win 了 win 了
上来我就想到康托展开了,很快啊!我就找到了答案的一个下界 \((k - 1)! + k\)。
然后根据样例发现答案是 \(k! + k\),于是打了高精。
根据信息论,我们很难让 \(k - 1\) 长度的排列对应 \(k!\) 的信息,但我们不需要让一个排列唯一对应 \(k!\) 的信息,因为 Alice 可以选择给出的排列。
这信息是 \(k \times (k - 1)!\) 的,因此当 \(n - (k - 1) \le k!\) 时都可能有解。下面我们要证明 \(k! + k - 1\) 是 \(n\) 的可达的上界。
考虑二分图匹配。左部点有 \(C_n^k\) 个,表示 Alice 得到的 \(k\) 个数。右部点有 \(P_n^{k -1}\) 个,表示 Bob 得到的排列。这时 \(n - k + 1\le k!\),我们要证明这二分图存在完美匹配。
每个左部点都可以引出 \(k!\) 条边,这是 Alice 可以选择给出的排列数。每个右部点连出的边数是 \(n - k + 1 \le k!\) 的,我们可以从未出现在排列中的 \(n - k + 1\) 个点中随便选一个,得到 \(k\) 个数。
这二分图是存在完美匹配的。具体地,我们从左侧选出 \(x\) 个点,向右侧连边数是 \(x\times k!\),而据鸽笼原理右侧被连到的点数 \(y\) 定 \(\ge x\)。根据 Hall 定理得证。
code
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii; typedef vector<int> vi; typedef vector<pii> vp; typedef long long ll;
template<typename T1, typename T2> T1 max(T1 a, T2 b) { return a > b ? a : b; }
template<typename T1, typename T2> T1 min(T1 a, T2 b) { return a < b ? a : b; }
#define rep(i,s,t) for (register int i = (s), i##__ = (t) + 1; i < i##__; ++ i)
#define pre(i,s,t) for (register int i = (s), i##__ = (t) - 1; i > i##__; -- i)
#define timer cerr << 1. * clock() / CLOCKS_PER_SEC << endl
#define file(fl) freopen(#fl".in", "r", stdin), freopen(#fl".out", "w", stdout)
#define iot ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define eb emplace_back
int k;
int a[100000];
void print() {
cout << a[a[0]];
pre(i,a[0]-1,1) printf("%04d",a[i]); cout << '\n';
}
void mul(const int& b) {
int i;
rep(i,1,a[0]) a[i] *= b;
for (i = 1; i <= a[0] or a[i] != 0; ++ i) {
a[i + 1] += a[i] / 10000, a[i] %= 10000;
} a[0] = i - 1;
}
void add(int b) {
int i;
for (i = 1; b; ++ i) a[i] += b % 10000, b /= 10000;
a[0] = max(a[0], i - 1);
for (i = 1; i <= a[0] or a[i] != 0; ++ i) {
a[i + 1] += a[i] / 10000, a[i] %= 10000;
} a[0] = i - 1;
}
signed main() {
file(win);
a[0] = 1, a[1] = 1;
cin >> k;
rep(i,2,k) mul(i);
add(k);
print();
}
39 与 93
39!
设 \(f(i, j, k)\) 是考虑前 \(i\) 个数,选了 \(j\) 个数删除,剩下的数 xor 值为 \(k\),则有转移
第一维可以压掉;第二维可以从大到小转移。
考虑得到优秀的边界条件。我们按 \(a\) 从小到大转移,这样当前的 xor 值不大于 \(2^{\log_2(a_i) + 1}\)。
总时间复杂度 \(O(s\sum a_i)\)。
code
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii; typedef vector<int> vi; typedef vector<pii> vp; typedef long long ll;
template<typename T1, typename T2> T1 max(T1 a, T2 b) { return a > b ? a : b; }
template<typename T1, typename T2> T1 min(T1 a, T2 b) { return a < b ? a : b; }
#define rep(i,s,t) for (register int i = (s), i##__ = (t) + 1; i < i##__; ++ i)
#define pre(i,s,t) for (register int i = (s), i##__ = (t) - 1; i > i##__; -- i)
#define file(fl) freopen(#fl".in", "r", stdin), freopen(#fl".out", "w", stdout)
#define iot ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define eb emplace_back
const int N = 1e6 + 10, mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll infll = 0x3f3f3f3f3f3f3f3f;
int n, s, b[N], ans, f[11][1 << 22], tmp[1 << 22], maxps[N];
inline void addi(int&a, const int& b) { (a += b) >= mod ? a -= mod : 0; }
signed main() {
cin >> n >> s;
rep(i,1,n) cin >> b[i];
sort(b + 1, b + 1 + n);
for (int i = 0; i <= 1e6; ++ i) maxps[i] = (1 << __lg(i) + 2) - 1;
f[0][0] = 1;
rep(i,1,n) {
memcpy(tmp, f[s - 1], sizeof(int) * (maxps[b[i]] + 1));
pre(j,s-1,1){
rep(k,0,maxps[b[i]])
addi(f[j][k], f[j - 1][k ^ b[i]]);
}
rep(k,0,maxps[b[i]])
addi(f[0][k], tmp[k ^ b[i]]);
}
cout << (f[n % s][0] - (n % s == 0) + mod) % mod << '\n';
}
Zbox的刷题I
场上没乘组合数 用 pgf 硬推假了
设 \(u\) 是期望做题数,\(v\) 是期望做题次数,答案即为 \(au + bv\)。
\(u\) 是好求的。一道题做 \(i\) 次做对的 pgf 是 \((1 - p) \dfrac{x}{1 - px}\),这样
\(v\) 是好求的。期望做题次数就是做 \(n\) 道题次数的最大值,考虑 \(\text{Min-Max}\) 容斥,就是
大概做完了吧。
code
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii; typedef vector<int> vi; typedef vector<pii> vp; typedef long long ll;
template<typename T1, typename T2> T1 max(T1 a, T2 b) { return a > b ? a : b; }
template<typename T1, typename T2> T1 min(T1 a, T2 b) { return a < b ? a : b; }
#define rep(i,s,t) for (register int i = (s), i##__ = (t) + 1; i < i##__; ++ i)
#define pre(i,s,t) for (register int i = (s), i##__ = (t) - 1; i > i##__; -- i)
#define file(fl) freopen(#fl".in", "r", stdin), freopen(#fl".out", "w", stdout)
#define iot ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define eb emplace_back
const int N = 2e6 + 10, mod = 998244353;
const int inf = 0x3f3f3f3f;
const ll infll = 0x3f3f3f3f3f3f3f3f;
int n, p, a, b, ans, fac[N], inv[N], prd[N], pw[N], iprd[N];
int qp(int a,int b){
int ans = 1;
while(b){
if(b & 1)ans = 1ll * ans * a % mod;
a = 1ll * a * a % mod;
b >>= 1;
} return ans;
}
int C(int n,int m){
return 1ll * fac[n] * inv[m] % mod * inv[n - m] % mod;
}
signed main(){
int u, v;
cin >> n >> u >> v >> a >> b;
p = 1ll * u * qp(v,mod - 2) % mod;fac[0] = inv[0] = 1;
rep(i,1,n) fac[i] = 1ll * fac[i - 1] * i % mod;
inv[n] = qp(fac[n],mod - 2);
pre(i,n - 1,1) inv[i] = 1ll * inv[i + 1] * (i + 1) % mod;
int ret = 1;prd[0] = 1;
rep(i,1,n) {
ret = 1ll * ret * p % mod;
pw[i] = (1 - ret + mod) % mod;
prd[i] = 1ll * prd[i - 1] * pw[i] % mod;
}
iprd[n] = qp(prd[n],mod - 2);
pre(i,n - 1,1) iprd[i] = 1ll * iprd[i + 1] * pw[i + 1] % mod;
rep(i,1,n) iprd[i] = 1ll * iprd[i] * prd[i - 1] % mod;
rep(i,1,n) {
ret = 1ll * C(n, i) * iprd[i] % mod;
if (i & 1) ans = (ans + ret) % mod;
else ans = (ans - ret + mod) % mod;
}
ans = 1ll * ans * b % mod;
ret = 1ll * a * n % mod * iprd[1] % mod;
ans = (ans + ret) % mod;
cout << ans << '\n';
}
以下是博客签名,与正文无关。
请按如下方式引用此页:
本文作者 joke3579,原文链接:https://www.cnblogs.com/joke3579/p/chitchat230227.html。
遵循 CC BY-NC-SA 4.0 协议。
请读者尽量不要在评论区发布与博客内文完全无关的评论,视情况可能删除。