闲话 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\),则有转移

\[f(i, j, k) = f(i - 1, j - 1, k \text{ xor } a_j) + f(i - 1, j, 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}\),这样

\[u = \left.\left(\left(\frac{(1 - p) x}{1 - px}\right)^n\right)'\right\rvert_{x = 1} = \frac{n}{1 - p} \]

\(v\) 是好求的。期望做题次数就是做 \(n\) 道题次数的最大值,考虑 \(\text{Min-Max}\) 容斥,就是

\[v = E[\max(S)] = \sum_{T\subseteq S} (-1)^{|T| + 1} E[\min(T)] = \sum_{T\subseteq S} \frac{(-1)^{|T| + 1}}{1 - p^{|T|}} = \sum_{i = 0}^{n - 1} (-1)^{i + 1} \binom{n}{i} \frac{1}{1 - p^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 = 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';
}
posted @ 2023-02-27 16:16  joke3579  阅读(108)  评论(4编辑  收藏  举报