• [BZOJ4403]序列统计


    Description

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

    (N,L,Rle 10^9)

    Solution

    (cnt = R - L + 1),即不同元素个数。

    问题等价为:选若干个不同的数按小到大的顺序分到序列上的前几个位置,那么这样构造出来的序列就是满足条件的。

    先枚举序列长度 (i) ,然后枚举出现了几种不同的数 (j) ,于是有:

    [sum_{i=1}^nsum_{j=1}^{cnt} {cntchoose j}{i - 1choose j - 1} ]

    (cnt schoose j) 是选 (j) 个不同的数,(i - 1choose j - 1) 是把 (j) 种数分配到长度为 (i) 的序列上去,相当于把序列分成 (j) 份,就是 (i-1) 个位置插 (j-1) 个板。

    观察这个式子的组合意义或者是用范德蒙德卷积化简:

    [sum_{i=1}^nsum_{j=1}^{cnt} {cntchoose j}{i - 1choose j - 1} = sum_{i=1}^n{i + cnt - 1choose cnt - 1} ]

    由组合恒等式:

    [sum_{i=0}^n{i + xchoose x}={n + x + 1choose x + 1} ]

    答案就是:

    [{n + cntchoose cnt} - 1 ]

    Lucas搞一下就好了。

    code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <fstream>
    
    typedef long long LL;
    typedef unsigned long long uLL;
    
    #define SZ(x) ((int)x.size())
    #define ALL(x) (x).begin(), (x).end()
    #define MP(x, y) std::make_pair(x, y)
    #define DEBUG(...) fprintf(stderr, __VA_ARGS__)
    #define GO cerr << "GO" << endl;
    
    using namespace std;
    
    inline void proc_status()
    {
    	ifstream t("/proc/self/status");
    	cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>()) << endl;
    }
    
    template<class T> inline T read() 
    {
    	register T x(0);
    	register char c;
    	register int f(1);
    	while (!isdigit(c = getchar())) if (c == '-') f = -1;
    	while (x = (x << 1) + (x << 3) + (c xor 48), isdigit(c = getchar()));
    	return x * f;
    }
    
    template<typename T> inline bool chkmin(T &a, T b) { return a > b ? a = b, 1 : 0; }
    template<typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
    
    const int maxN = (int) 1e6 + 3;
    const int mod = (int) 1e6 + 3;
    
    int fac[maxN + 2], ifac[maxN + 2];
    
    LL qpow(LL a, LL b) 
    {
    	LL ans(1);
    	while (b)
    	{
    		if (b & 1)
    			ans = ans * a % mod;
    		a = a * a % mod;
    		b >>= 1;
    	}
    	return ans;
    }
    
    void init()
    {
    	fac[0] = 1;
    	for (register int i = 1; i < mod; ++i) fac[i] = (LL) fac[i - 1] * i % mod;
    	ifac[mod - 1] = qpow(fac[mod - 1], mod - 2);
    	for (register int i = mod - 2; i >= 0; --i) ifac[i] = (LL) ifac[i + 1] * (i + 1) % mod;
    }
    
    int C(int n, int m)
    {
    	if (n < m) return 0;
    	return (LL)fac[n] * ifac[m] % mod * ifac[n - m] % mod;
    }
    
    int Lucas(LL n, LL m)
    {
    	if (n < m) return 0;
    	if (m == 0) return 1;
    	return (LL)Lucas(n / mod, m / mod) * C(n % mod, m % mod) % mod;
    }
    
    int main() 
    {
    #ifndef ONLINE_JUDGE
    	freopen("BZOJ4403.in", "r", stdin);
    	freopen("BZOJ4403.out", "w", stdout);
    #endif
    	init();
    	int T;
    	cin >> T;
    	while (T--)
    	{
    		LL n, R, L, cnt;
    		cin >> n >> L >> R;
    		cnt = R - L + 1;
    		cout << ((LL)Lucas(n + cnt, cnt) + mod - 1) % mod << endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    Sencha Touch 框架快速入门系列
    dotTrace 使用说明
    CQRS架构中同步服务的一种实现方式
    C#中循环结构的效率问题
    面向领域驱动架构的查询实现方式
    最佳 jQuery
    DWZ&MVC的探索系列——Demo演示效果
    在Windows Azure中实现和调试一个WCF服务(上)
    现代软件工程开发体验:结对编程
    结对编程是什么?
  • 原文地址:https://www.cnblogs.com/cnyali-Tea/p/11498106.html
Copyright © 2020-2023  润新知