bzoj4403: 序列统计

题意

给定三个正整数N、L和R,统计长度在1到N之间,元素大小都在L到R之间的单调不降序列的数量。输出答案对10^6+3取模的结果。


自己xjbyy的解法

设m=r-l+1.
那么我们先枚举一个i表示这个单调不降序列有多少个不同的数, 那么Cin就是选出i个不同的数的方案数,然后我们看剩下的n-i个数,很明显他们可以不选,或者成为这i个数中的一个,此时就对应球盒模型“n-i个相同的球放入i个盒子,盒子可以为空的方案数”,因为球可以不放,我们就新增一个盒子不放的球单独放到这个盒子里,哪么就是“n-i个相同的球放入i+1个盒子,盒子可以为空的方案数”了,这个就等于Cim于是最后的答案就是
ni=1CinCim,然后我们可以考虑化简他:
原式=ni=1CinCmim我们考察一下这个式子的意义,就是有两个盒子,一个盒子有n个球,一个盒子有m个球,然后一个盒子选i个球1<=i<=n,两个盒子一共选m个球的方案数,所以我们完全可以把两个盒子的球混在一起然后选出m个球,那就是Cmn+m了,我们发现,这样算的话,i=0这种情况也被算进去了,所以我们应该再减去一个1,哪么最后的答案就是Cmn+m1了。
r


突然清醒

突然发现自己是zz:我们这个问题就直接相当于把”n个球放入m个盒子,盒子可以为空,球可以不选”,再减去n个球一个都不选的情况,那就直接是Cmn+m-1了.

#include<cstdio>
#include<algorithm>

const int P = 1e6 + 3;
typedef long long ll;
int T, n, m;
ll jx[P], jx_rev[P];

int C (int n, int m) {
    if (m > n) return 0;
    return jx[n] * jx_rev[m] % P * jx_rev[n - m] % P;
}

ll Lucas (int n, int m) {
    if (m > n) return 0ll;
    if (n < P) return C (n, m);
    int k = C (n % P, m % P);
    if (k) return Lucas (n / P, m / P) * k % P;
    return 0ll;
}

ll quick_power (ll a, ll b) {
    ll ret = 1;
    for (; b; a = a * a % P, b >>= 1) if (b & 1) ret = ret * a % P;
    return ret;
}

int main () {
    scanf ("%d", &T);
    int l, r;
    jx[0] = 1; for (int i = 1; i < P; ++i) jx[i] = jx[i - 1] * i % P;
    jx_rev[P - 1] = quick_power (jx[P - 1], P - 2);
    for (int i = P - 2; ~i; --i) jx_rev[i] = jx_rev[i + 1] * (i + 1) % P;
    while (T--) {
        scanf ("%d%d%d", &n, &l, &r), m = r - l + 1;
        printf ("%lld\n", (Lucas (n + m, m) - 1 + P) % P);
    }
    return 0;
}
posted @ 2017-01-28 13:44  DraZxlnDdt  阅读(139)  评论(0编辑  收藏  举报