zoukankan      html  css  js  c++  java
  • CF1550D Excellent Arrays 题解

    Codeforces
    Luogu

    Description.

    给定一个序列,问有多少种合法情况,使得它的权值最大。
    一个序列 \(\{a_i\}\) 合法,当且仅当:

    • \(\forall i\in[1,n],a_i\in[L,R]\)

    一个序列 \(\{a_i\}\) 的权值定义为 \(\sum_{i=1}^n\sum_{j=i+1}^n[a_i+a_j=i+j]\)

    Solution.

    首先,定义序列 \(\{b_i\}\) 满足 \(\forall i\in[1,n],b_i=a_i-i\)
    那序列 \(a_i\) 的权值即为 \(\sum_{i=1}^n\sum_{j=i+1}^n[b_i+b_j=0]\)
    显然权值上界一定是 \(\begin{cases}\frac n2\times\frac n2&n\equiv0\pmod2\\\frac{n-1}2\times\frac{n+1}2&n\equiv1\pmod2\end{cases}\)
    而且如果取 \(|b_i|=\left\lfloor\frac{r-l}2\right\rfloor\) 必定能取到这个上界
    所以我们证明了答案数组 \(\forall i\in[1,n],|a_i-i|=x\)

    我们先不考虑复杂度,考虑枚举这个 \(x\)
    枚举之后必定左边一小段 \(b_i=x\),右边一小段 \(b_i=-x\),其他都可
    然后都可的直接上一个组合数即可

    同时,考虑复杂度是 \(O(V)\) 的,不可接受。
    我们发现只有前 \(n\) 个和后 \(n\)\(x\) 的取值有区别,其他全都是都可以取。
    所以复杂度被优化成了 \(O(n)\),可以 AC 此题。

    Coding.

    点击查看逊人代码
    //是啊……你就是那只鬼了……所以被你碰到以后,就轮到我变成鬼了{{{
    #include<bits/stdc++.h>
    using namespace std;typedef long long ll;
    template<typename T>inline void read(T &x)
    {
    	x=0;char c=getchar(),f=0;
    	for(;c<'0'||c>'9';c=getchar()) if(c=='-') f=1;
    	for(;c>='0'&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    	if(f) x=-x;
    }/*}}}*/
    #define int long long
    int fc[1000005],fi[1000005];const int P=1e9+7;
    int n,m,rs,l,r,a[1000005];char v[1000005];
    inline int ksm(int x,int q=P-2) {int r=1;for(;q;q>>=1,x=1ll*x*x%P) if(q&1) r=1ll*r*x%P;return r;}
    inline void init()
    {
    	fc[0]=1;for(int i=1;i<=1000000;i++) fc[i]=1ll*fc[i-1]*i%P;
    	fi[1000000]=ksm(fc[1000000]);for(int i=1000000;i;i--) fi[i-1]=1ll*fi[i]*i%P;
    }
    inline int C(int n,int m) {return n<0||m<0||n<m?0:1ll*fc[n]*fi[m]%P*fi[n-m]%P;}
    inline int Calc1(int x)
    {
    	if(x<=0) return 0;
    	int a=max(x+l-1,0ll),b=max(n-r+x,0ll);if(a+b>n) return 0;
    	if(n&1) return (C(n-a-b,n/2-a)+C(n-a-b,n/2-a+1))%P;
    	else return C(n-a-b,n/2-a);
    }
    inline int Calc2()
    {
    	if(n&1) return (C(n,n/2)+C(n,n/2+1))%P;
    	else return C(n,n/2);
    }
    inline void solve()
    {
    	int rs=0;read(n),read(l),read(r);
    	for(int i=min(-l,r-n);i<=min(n-l,r);i++) rs=(rs+Calc1(i))%P;
    	printf("%lld\n",(rs+max(min(-l,r-n)-1,0ll)*Calc2())%P);
    }
    signed main() {init();int Ca;for(read(Ca);Ca--;) solve();return 0;}
    
  • 相关阅读:
    iOS开发-Sqlite
    iOS开发-HTTP协议
    iOS开发
    iOS 开发小记 (八)
    iOS
    iOS开发-基础框架
    Java门面模式
    Linux常用命令
    canal使用小结
    MySQL隔离级别的测试
  • 原文地址:https://www.cnblogs.com/pealfrog/p/15067441.html
Copyright © 2011-2022 走看看