当前位置:编程学习 > C/C++ >>

HDU4373 Mysterious For

2012 Multi-University Training Contest 8
题意:
m个for循环嵌套,有两种形式,第一类从1开始到n,第二类从上一层循环当前数开始到n,第一层一定是第一种类型,问总的循环的次数对364875103取余的结果。

首先可以看出,每一个第一类循环都是一个新的开始,与前面的状态无关,所以可以把m个嵌套分为几个不同的部分,每一个部分由第一类循环开始,最终结果相乘就可以。
剩下的就是第二类循环的问题,假设一个m层循环,最大到n,
只有第一层:循环n次。
只有前两层:循环n + (n - 1) + ... + 1 = (n + 1) * n / 2 = C(n + 1, 1)
只有前三层:
      (n + 1) * n / 2 + n * (n - 1) / 2 + ... + 1
    = (1 + 2 + ... + n) / 2 + (1 + 4 + ... + n^2) / 2
    = (n + 1) * n / 2 / 2 + n * (n + 1) * (2n + 1) / 6 / 2
    = (n + 2) * (n + 1) * n / 6 = C(n + 2, 2)
……
找规律得第m层:C(n + m - 1, m)

接下来的问题就是如何求出这些东西对364875103的模,由于n和m都非常大,暴力统计必然是不行的。
364875103 = 97 * 3761599 (比赛时候哪有心情拆数玩,这个太不厚道了)
Lucas(n, m, p) = c(n % p,m % p) * Lucas(n / p, m / p, p);
用Lucas定理分别求出两个质数的余数,然后利用中国剩余定理求出对364875103的余数。

[cpp] 
#include <cstdio> 
#include <cstring> 
#include <algorithm> 
using namespace std; 
const int MAXK = 20; 
const int MOD1 = 97; 
const int MOD2 = 3761599; 
const int MOD = MOD1 * MOD2; 
 
int n, m, k; 
int a[MAXK]; 
__int64 p1[MOD1], p2[MOD2]; 
__int64 c1, c2; www.zzzyk.com
 
__int64 pow_mod(__int64 x, __int64 y, __int64 mod) 

    __int64 res = 1; 
    while(y) 
    { 
        if(y & 1) 
        { 
            res = (res * x) % mod; 
        } 
        x = (x * x) % mod; 
        y >>= 1; 
    } 
    return res; 

 
__int64 cm(__int64 n, __int64 m, __int64 mod, __int64 p[]) 

    if(n < m) 
    { 
        return 0; 
    } 
    __int64 res = (p[n] * pow_mod(p[m], mod - 2, mod)) % mod; 
    return (res * pow_mod(p[n - m], mod - 2, mod)) % mod; 

 
__int64 lucas(__int64 n, __int64 m, __int64 mod, __int64 p[]) 

    __int64 res = 1; 
    while(n && m && res) 
    { 
        res = (res * cm(n % mod, m % mod, mod, p)) % mod; 
        n /= mod; 
        m /= mod; 
    } 
    return res; 

 
void init() 

    p1[0] = p2[0] = 1; 
    for(int i=1;i<MOD1;++i) 
    { 
        p1[i] = (p1[i-1] * i) % MOD1; 
    } 
    for(int i=1;i<MOD2;++i) 
    { 
        p2[i] = (p2[i-1] * i) % MOD2; 
    } 
    c1 = MOD2 * pow_mod(MOD2, MOD1 - 2, MOD1); 
    c2 = MOD1 * pow_mod(MOD1, MOD2 - 2, MOD2); 

 
int main() 

    init(); 
    int caseNumber; 
    scanf("%d", &caseNumber); 
    for(int cas=1;cas<=caseNumber;++cas) 
    { 
        scanf("%d%d%d", &n, &m, &k); 
        for(int i=0;i<k;++i) 
        { 
            scanf("%d", &a[i]); 
        } 
        a[k] = m; 
        __int64 ans = 1; 
        for(int i=0;i<k;++i) 
        { 
            __int64 m1 = lucas(a[i+1] - a[i] + n - 1, a[i+1] - a[i], MOD1, p1); 
            __int64 m2 = lucas(a[i+1] - a[i] + n - 1, a[i+1] - a[i], MOD2, p2); 
            __int64 mm = (m1 * c1 + m2 * c2) % MOD; 
            ans = (ans * mm) % MOD; 
        } 
        printf("Case #%d: %I64d\n", cas, ans); 
    } 
    return 0; 

补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,