1.stone
根据期望的线性性,答案 E(t) = P2 + P3 + · · · + Pn + 1,其中 Pi 是第 i 堆石子在第 1 堆之前被取走的概率。
考虑第 i 堆,可以发现其他堆都不会影响这两堆,因此相当于只要考虑只有这两堆的情况,因此概率即为。
因此答案即为,直接计算即可。
时间复杂度: Θ(n)。
2.memory
对于每个 x,考虑如果用它来压缩那么可以达到的最优解,设为 F(x)。
假如给定一个 x,想要求 F(x),那么可以通过二分贪心在 Θ(n log2 n) 的时间内算出。
直接对于所有 x 都暴力计算即可得到 Θ(nm log2 n) 的复杂度,可以通过子任务1, 2。
如果我们以随机顺序遍历所有 x,则在期望情况下,新的 F(x) 比当前所有F 的值都要小的 x 个数的期望应该是 ∑ 1/i,这是调和级数,为 Θ(ln n)。
于是我们只对于这些 x 二分即可:我们令答案为 ans − 1 并贪心,即可判断当前的 x 是否满足条件。
时间复杂度: Θ(nm + n ln n log2 n)。
使最大值最小,很显然这是一个二分。
60分做法
这个部分分还是非常好拿的,只需要枚举每一个x并二分求答案即可。
时间复杂度:
100分做法
其实就是再60分做法的基础上做一个类似与搜索的最优化剪枝的优化。
我们可以发现,当我们枚举到一个x的时候,当且仅当在的基础上check(ans-1)成立(ans为区间[1,x-1]求得的最小值),这个x才有可能对答案产生贡献,所以我们在每次二分前根据check(ans-1)的情况去决定是否对x进行二分答案即可。
注意,为了防止自己被卡,最好将x的枚举顺序打乱后再进行枚举。
code:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<algorithm>
#define ll long long
#define INF 0x7fffffff
#define re register
#define rep(i,a,b) for(int i = (a); i <= (b); i++)
#define qwq printf("qwq
");
using namespace std;
int read()
{
register int x = 0,f = 1;register char ch;
ch = getchar();
while(ch > '9' || ch < '0'){if(ch == '-') f = -f;ch = getchar();}
while(ch <= '9' && ch >= '0'){x = x * 10 + ch - 48;ch = getchar();}
return x * f;
}
int n,m,k,l,r,ti,mid,ans,sum,a[100005],b[100005],c[100005];
bool check(int l)
{
int cnt = 1; sum = 0;
for(int i = 1; i <= n; i++)
{
if(sum + b[i] > l) cnt++,sum = 0;
sum += b[i];
if(cnt > k) return false;
}
return true;
}
int cmp(int a,int b) {return rand() % 2;}
int main()
{
n = read(); m = read(); k = read();
srand(time(0));
for(int i = 1; i < m; i++) c[i] = i;
sort(c + 1, c + m,cmp);
for(int i = 1; i <= n; i++) a[i] = read();
ans = INF;
for(int i = 1; i < m; i++)
{
int y = c[i];
l = 0;
for(int j = 1; j <= n; j++) b[j] = (a[j] + y) % m,sum += b[j],l = max(l,b[j]);
r = min(ans,sum);
while(l < r)
{
mid = (l + r) >> 1;
if(check(mid)) r = mid,ans = min(ans,r);
else l = mid + 1;
}
}
printf("%d
",ans);
return 0;
}
3.subset
显然我们只会选择 n 的约数,因为如果选了其他的那么最小公倍数一定不是 n。
考虑对 n 进行分解,设 n = pα 1 1pα 2 2 · · · pα kk。那么我们要求选的数字满足:对于每个 i ∈ [1, k],均存在一个数在 pi 中是 0 次方,也存在一个数在 pi 中是 αi 次方。
直接计算并不容易,考虑容斥原理:如果只有一个 pα,那么我们用所有情况去掉不存在 0 次方的情况,再去掉不存在 α 次方的情况,然后加上都不存在的情况即可。
然后对于原问题,我们可以 Θ(4k) 枚举每个质因数是上面四种情况中的哪一种,然后计算出这种情况下的方案数即可。时间复杂度: Θ(4ω(n)ω(n)),可以通过子任务1, 2。
考虑如何进行优化。注意到对于第一种情况,方案数为 (αi + 1),第二种和第三种情况都是 αi,而第四种是 (αi − 1)。因此,我们可以转而枚举方案数的可能性,这只有三种,因此枚举的复杂度从 Θ(4k) 降到了 Θ(3k)。
值得一提的是,这里对 n 进行分解是本题的难点: Θ(√n) 的复杂度并不可以接受,但我们并不需要真的得到 p1, p2, · · · , pk,而是只要知道 α1, α2, · · · , αk 即可。
我们考虑先分解出所有 pi ≤ √3 n 的 pα i i,那么剩余部分只有 p, p2, pq 三种,其中p, q 都是质数。
那么我们先使用 Miller Rabin 算法判断 p 的情况,然后开根号后平方判断 p2 的情况,剩余的情况就是 pq 的情况了。
时间复杂度: Θ(√3 n + 3ω(n)ω(n))。