zoukankan      html  css  js  c++  java
  • 【解题报告】2019正睿Day2

    1.stone

    根据期望的线性性,答案 E(t) = P2 + P3 + · · · + Pn + 1,其中 Pi 是第 i 堆石子在第 1 堆之前被取走的概率。
    考虑第 i 堆,可以发现其他堆都不会影响这两堆,因此相当于只要考虑只有这两堆的情况,因此概率即为aia1+aifrac{ai}{a1 + ai}
    因此答案即为i=2naia1+ai+1sum_{i=2}^{n}{frac{ai}{a1 + ai}+1},直接计算即可。
    时间复杂度: Θ(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并二分求答案即可。

    时间复杂度:O(nmlogn)O(nmlogn)

    100分做法

    其实就是再60分做法的基础上做一个类似与搜索的最优化剪枝的优化。

    我们可以发现,当我们枚举到一个x的时候,当且仅当在a[i]=(a[i]+x)%ma[i]=(a[i]+x)\%m的基础上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))。

  • 相关阅读:
    棋盘型动态规划 之 CODE[VS] 1220 数字三角形
    棋盘型动态规划 之 CODE[VS] 1219 骑士游历 1997年
    棋盘型动态规划 之 CODE[VS] 1169 传纸条 2008年NOIP全国联赛提高组
    棋盘型动态规划 之 CODE[VS] 1010 过河卒 2002年NOIP全国联赛普及组
    [实验]自举?只不过是电容和二极管捣的乱
    [嵌入式]I2C协议指东
    [语法]C语言中二维数组做输入参数
    深入类方法。
    今天周六祝大家休息开心,我还在奋斗....
    我们一起来一把.....现在学习真的好累,一天下来脑袋要炸
  • 原文地址:https://www.cnblogs.com/aurorapolaris/p/13449119.html
Copyright © 2011-2022 走看看