zoukankan      html  css  js  c++  java
  • CF886E Maximum Element

    $ color{#0066ff}{ 题目描述 }$

    从前有一个叫Petya的神仙,嫌自己的序列求max太慢了,于是将序列求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++;
                if(offset==k)return ans;
            }
        }
        return ans;
    }
    //大括号换行,无多余空格,by wucstdio
    

    这个函数的原理是,如果碰到一个数后面连续的(k)个数都比它小,那么就把这个数当做序列的最大值。

    然而很显然,这份代码是错的。这位(Petya)神仙对它出错的情况很感兴趣。于是他找到了同为神仙的你,让你求有多少长度为(n)的排列,这个函数会返回错误的结果,即返回值不是(n)。由于答案过大,你只需要输出这个数对(10^9+7)取模的结果。

    (color{#0066ff}{输入格式})

    一行两个正整数(n)(k),表示排列的长度和上面那份代码里的(k)

    (color{#0066ff}{输出格式})

    一行一个整数,表示答案对(10^9+7) 取模后的值。

    (color{#0066ff}{输入样例})

    5 2
    
        
    5 3
    
        
    6 3
    

    (color{#0066ff}{输出样例})

    22
    
    6
    
    84
    

    (color{#0066ff}{数据范围与提示})

    Permutations from second example:

    ([4,1,2,3,5]) , $[4,1,3,2,5] $, ([4,2,1,3,5] ,) $[4,2,3,1,5] $, $[4,3,1,2,5] $, ([4,3,2,1,5]) .

    (color{#0066ff}{题解})

    如果正着算,比如 4 2 1 6 5 3,k=2,那么会出现两个符合条件的,但是我们只算一次,所以这样不好算

    我们考虑单步容斥,用总数(n!)减去最大值是n的

    考虑排列中n的位置,那么n前面的数不能出现题目所说的情况

    于是我们设(f[i])为长度为i的排列,不会出现一个数后面有k个比它小的数的方案数

    还是考虑i的位置来转移,因为i是最大的,所以显然转移为(f_i=sum_{j=i-k+1}^if_{j-1}C_{i-1}^{i-j}*(i-j)!=(i-1)!*sum_{j=i-k}^{i-1}frac{f_j}{j!})

    显然后面的东西可以前缀和优化一下,于是我们可以(O(n))求出f数组!

    然后开始统计答案,枚举n的位置i(ans=sum_{i=1}^nf_{i-1}*C_{n-1}^{n-i}*(n-i)!=(n-1)!*sum_{i=1}^nfrac{f_{i-1}}{(i-1)!})

    直接线性统计答案即可

    #include<bits/stdc++.h>
    #define LL long long
    LL in() {
    	char ch; LL x = 0, f = 1;
    	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    	return x * f;
    }
    const int maxn = 5e6 + 10;
    const int mod = 1e9 + 7;
    int n, k;
    LL fac[maxn], inv[maxn];
    LL f[maxn], s[maxn];
    LL ksm(LL x, LL y) {
    	LL re = 1LL;
    	while(y) {
    		if(y & 1) re = re * x % mod;
    		x = x * x % mod;
    		y >>= 1;
    	}
    	return re;
    }
    int main() {
    	n = in(), k = in();
    	fac[0] = 1;
    	for(LL i = 1; i <= n; i++) fac[i] = fac[i - 1] * i % mod;
    	inv[n] = ksm(fac[n], mod - 2);
    	for(LL i = n - 1; i >= 0; i--) inv[i] = inv[i + 1] * (i + 1) % mod;
    	f[0] = s[0] = 1;
    	for(int i = 1; i <= n; i++) {
    		f[i] = (fac[i - 1] * (s[i - 1] - (i - k - 1 >= 0? s[i - k - 1] : 0) + mod)) % mod;
    		s[i] = (f[i] * inv[i] % mod + s[i - 1]) % mod;
    	}
    	LL ans = 0;
    	for(int i = 1; i <= n; i++) (ans += fac[n - 1] * f[i - 1] % mod * inv[i - 1] % mod) %= mod;
    	printf("%lld", (fac[n] - ans + mod) % mod);
    	return 0;
    }
    
  • 相关阅读:
    Callable、Future和FutureTask使用说明
    WebSocket原理及与http1.0/1.1 long poll和 ajax轮询的区别【转自知乎】
    jvm内存模型及分配参数
    CyclicBarrier 使用说明
    【LOJ6515】贪玩蓝月
    【LOJ6482】LJJ 爱数数 数论
    【CF1063F】String Journey 哈希
    【CF1063D】Candies for Children 数学
    【XSY2851】蛋糕 数学
    2018百度之星大赛游记
  • 原文地址:https://www.cnblogs.com/olinr/p/10484280.html
Copyright © 2011-2022 走看看