• CF886E Maximum Element


    link

    题目大意:Petya写了一个假的序列求max

    int fast_max(int n, int a[]) {
    	int ans = 0;
    	int offset = 0;
    	for (int i = 0; i < n; ++i)
    		if (ans < a[i]) {
    			ans = a[i];
    			offset = 0;
    		} else {
    			offset = offset + 1;
    			if (offset == k)
    			return ans;
    		}
    	return ans;
    }
    

    现在请问对于n的所有排列和代码中的k,调用这个函数返回的不是n的方案数

    题解:根据代码 如果序列中出现一个位置的后面连续k个数比这个数小那么就返回这个数

    这是一个或的关系,我们容斥一下,方案数为n!-合法方案数,显然合法方案数为序列中n的前面不存在

    一个位置的后面连续k个数比这个数小那么就返回这个数

    那么我们设(f_i​)为i的排列不存在某个位置的后面连续k个数比这个数小的情况

    我们考虑枚举最大值(i)摆放位置,由于这个值也不能满足条件,所以这个数后面最多有k-1个数,显然我们有dp方程(f_i=sum_{j=i-k+1}^{i}f_{j-1}{(i-1)}^{underline{i-j}}),不过这个方程是O(nk)的,我们可以把排列数拆一下,写成(f_i=(i-1)!sum_{j=i-k+1}^ifrac{f_{j-1}}{(j-1)!}),我们发现把(frac{f_i}{i!})搞个前缀和就能做到O(n)​转移了。

    然后我们考虑收集答案,我们还是考虑枚举(n)摆放位置,就有(Ans=sum_{i=1}^nf_{i-1}(n-1)^{underline{n-i}}),然后我们发现收集答案就是O(n)的就可以瞎几把写了。

    难点主要是设状态。。。

    code:

    #include <cstdio>
    using namespace std;
    
    const int xkj = 1000000007;
    int n, k, fac[1000010], inv[1000010], f[1000010], s[1000010];
    
    int qpow(int x, int y)
    {
    	int res = 1;
    	for (x %= xkj; y > 0; y >>= 1, x = x * (long long)x % xkj)
    		if (y & 1) res = res * (long long)x % xkj;
    	return res;
    }
    
    int main()
    {
    	scanf("%d%d", &n, &k);
    	fac[0] = 1;
    	for (int i = 1; i <= n; i++) fac[i] = fac[i - 1] * (long long)i % xkj;
    	inv[n] = qpow(fac[n], xkj - 2);
    	for (int i = n; i >= 1; i--) inv[i - 1] = inv[i] * (long long)i % xkj;
    	f[0] = s[0] = 1;
    	for (int i = 1; i <= n; i++)
    	{
    		f[i] = fac[i - 1] * (long long)(s[i - 1] - (i > k ? s[i - k - 1] : 0) + xkj) % xkj;
    		s[i] = (f[i] * (long long)inv[i] + s[i - 1]) % xkj;
    	}
    	int ans = 0;
    	for (int i = 1; i <= n; i++)
    	{
    		ans = (ans + f[i - 1] * (long long)fac[n - 1] % xkj * inv[i - 1] % xkj) % xkj;
    	}
    	printf("%d
    ", (fac[n] - ans + xkj) % xkj);
    	return 0;
    }
    
  • 相关阅读:
    bash脚本编程之数组和字符串处理
    Linux启动流程简介以及各启动阶段失败的恢复方法
    Linux路由表的重要性以及配置
    Linux终端和伪终端简述
    Linux九阴真经之无影剑残卷9(Shell脚本编程进阶)
    Linux九阴真经之无影剑残卷8(计划任务)
    Linux九阴真经之无影剑残卷7(进程管理)
    Linux九阴真经之无影剑残卷5(Linux静态路由的实现)
    Linux九阴真经之无影剑残卷4(创建虚拟内存--swap)
    Linux九阴真经之无影剑残卷3(将home目录搬到新分区)
  • 原文地址:https://www.cnblogs.com/oier/p/10483117.html
Copyright © 2020-2023  润新知