【笔记】简单信息量计算
我们都听过基于比较的排序复杂度下限是 \(\mathcal{O}(N\log N)\) 的,那么下限是怎么求的?
我们知道长度为 \(n\) 的排列有 \(n!\) 个,这就是总信息量。每次排序,只会返回 \(>\) 或 \(<\) 只有两种情况。所以如果策略得当,进行 \(k\) 次比较最多可以区分 \(2^k\) 钟情况。排序需要满足 \(2^k \ge n!\),所以 \(k\) 是 \(\mathcal{O}(\log n! = n\log n)\) 级别的。
那么如果是 \(0/1\) 序列的基于比较的排序呢?总信息量是 \(2^n\),所以 \(k = \log 2^n = n\)。具体的策略是从前往后扫一遍即可得到最大值,然后再扫一遍即可知道每个 \(0/1\),也有实现更精密的线性做法。
再举一个简单的例子,有 \(n\) 份核酸检测样本,已知其中只有一份样本是阳性,怎样用最少的次数查出阳性样本。
由于只有一份是阳性,所以总信息量是 \(n\),而每次检测返回阴/阳两种情况,所以需要的次数是 \(k = \log n\) 次。具体的策略是混合一些样品,其中第 \(i\) 份样品混合了 \(n\) 个样本中二进制下第 \(i\) 位为 \(1\) 的样本。每次检测就可以知道阳性样本编号第 \(i\) 位是 \(0/1\)。
恰好有 \(a\) 个阳性时 \(k = \log \binom{n}{a} < \log 2^n = n\),所以可以构造比直接检测更优的方案。但现实中我们并不知道有多少个阳性。
Problem - 643F - Codeforces
难度跨度有点大。
这里我们是要求的是最大的总信息量。
那么我们看信息是什么。某头熊在某一天睡觉就是信息。\(n\) 头熊,最多有 \(p\) 头熊睡觉,有 \(t\) 天。那么最多可以区分的总信息量是 \(\sum\limits_{i = 0}^{p} \binom{n}{i}t ^ i\),同时我们又可以构造出这样一种策略,所以这就是最大信息量。
#define N 150
typedef unsigned ui;
int n, p, q; ui c[N], a[N], ed;
void calc(int x){
rp(i, x)a[i] = n - i + 1;
rp(i, x){
int k = i;
rp(j, x){
ui w = gcd(a[j], k);
k /= w, a[j] /= w;
if(1 == k)break;
}
}
c[x] = 1;
rp(i, x)c[x] *= a[i];
}
int main() {
read(n, p, q);
p = min(p, n - 1);
rep(i, 0, p)calc(i);
rp(t, q){
ui cur = 1, s = 0;
rep(i, 0, p){
s += cur * c[i];
cur *= t;
}
ed ^= s * t;
}
cout << ed << endl;
return 0;
}