HDU 4767——Bell

昨天比赛被虐的这个题目。

今天听斌牛讲过他的思路后就A掉了。

题目的意思是要你求出bell数的第n项对95041567取模。

首先,95041567=31*37*41*43*47;

然后取模就是先分别取模,然后就用中国剩余定理合并了。

现在的问题就是如何求出来B[n]对95041567分别取模的结果了哦。

不错,现在你缺少的就是一个公式——B[P^m+n]==(B[n]+B[n+1])%P——P为任一个质数(来自维基百科)。

这样的话我们就可以递推了哦。

从大的开始往小的递推,每次减去一个最大的P^m,知道推到一个n<=P,用记忆化<map>就A掉了。

代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#define N 95041567
#define maxn 2147483647
#define ll long long
using namespace std;

llm[5]={31,37,41,43,47},a[5],n,t;
llf[5][50][50];
map<ll,ll>ss;

void function()
{
    for (lli=0; i<5; i++)
    {
        f[i][0][0]=1;
        f[i][1][1]=1;
        for (llj=2; j<=m[i]; j++)
        {
            f[i][j][1]=f[i][j-1][j-1];
            for (llk=2; k<=j; k++)
                f[i][j][k]=(f[i][j][k-1]+f[i][j-1][k-1])%m[i];
        }
    }
}

llget(lltot,llx)
{
    if (tot<=m[x]) return f[x][tot][tot];
    if (ss[tot]!=0) return ss[tot];
    llM=1,cur=m[x];
    while (cur*m[x]<=tot) M++,cur*=m[x];
    ss[tot]=(M*get(tot-cur,x)+get(tot-cur+1,x))%m[x];
    return ss[tot];
}

void exgcd(llA,llB,ll& x,ll& y)
{
    if (!B) {  x=1,y=0; }
    else { exgcd(B,A%B,y,x); y-=A/B*x; }
}

llchina()
{
    lld,x=0,y;
    for (lli=0; i<5; i++)
    {
        llw=N/m[i];
        exgcd(m[i],w,d,y);
        x=(x+y*w*a[i])%N;
    }
    return (x+N)%N;
}

int main()
{
    function();
    cin>>t;
    while (t--)
    {
        cin>>n;
        for (lli=0; i<5; i++)
        {
            ss.clear();
            a[i]=get(n,i);
        }
        cout<<china()<<"
";
    }
    return 0;
}

 

如有转载,请注明出处(http://www.cnblogs.com/lochan)
原文地址:https://www.cnblogs.com/lochan/p/3347066.html