HDU 4767 Bell(矩阵+中国剩余定理)

时间:2023-03-09 04:11:46
HDU 4767 Bell(矩阵+中国剩余定理)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4767

题意:给出n。求n有多少种划分集合的方式,即bell(n)

思路:

HDU 4767 Bell(矩阵+中国剩余定理)

#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <map>

#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define abs(x) ((x)>=0?(x):-(x))
#define i64 long long
#define u32 unsigned int
#define u64 unsigned long long
#define clr(x,y) memset(x,y,sizeof(x))
#define CLR(x) x.clear()
#define ph(x) push(x)
#define pb(x) push_back(x)
#define Len(x) x.length()
#define SZ(x) x.size()
#define PI acos(-1.0)
#define sqr(x) ((x)*(x))
#define MP(x,y) make_pair(x,y)

#define FOR0(i,x) for(i=0;i<x;i++)
#define FOR1(i,x) for(i=1;i<=x;i++)
#define FOR(i,a,b) for(i=a;i<=b;i++)
#define DOW0(i,x) for(i=x;i>=0;i--)
#define DOW1(i,x) for(i=x;i>=1;i--)
#define DOW(i,a,b) for(i=a;i>=b;i--)

#define rush() int CC;for(scanf("%d",&CC);CC--;)
#define Rush(n)  while(scanf("%d",&n)!=-1)
using namespace std;

void RD(int &x){scanf("%d",&x);}
void RD(i64 &x){scanf("%lld",&x);}
void RD(u32 &x){scanf("%u",&x);}
void RD(double &x){scanf("%lf",&x);}
void RD(int &x,int &y){scanf("%d%d",&x,&y);}
void RD(i64 &x,i64 &y){scanf("%lld%lld",&x,&y);}
void RD(u32 &x,u32 &y){scanf("%u%u",&x,&y);}
void RD(double &x,double &y){scanf("%lf%lf",&x,&y);}
void RD(int &x,int &y,int &z){scanf("%d%d%d",&x,&y,&z);}
void RD(i64 &x,i64 &y,i64 &z){scanf("%lld%lld%lld",&x,&y,&z);}
void RD(u32 &x,u32 &y,u32 &z){scanf("%u%u%u",&x,&y,&z);}
void RD(double &x,double &y,double &z){scanf("%lf%lf%lf",&x,&y,&z);}
void RD(char &x){x=getchar();}
void RD(char *s){scanf("%s",s);}
void RD(string &s){cin>>s;}

void PR(int x) {printf("%d\n",x);}
void PR(i64 x) {printf("%I64d\n",x);}
void PR(u32 x) {printf("%u\n",x);}
void PR(u64 x) {printf("%llu\n",x);}
void PR(double x) {printf("%.3lf\n",x);}
void PR(char x) {printf("%c\n",x);}
void PR(char *x) {printf("%s\n",x);}
void PR(string x) {cout<<x<<endl;}

const i64 inf=((i64)1)<<60;
const double dinf=1e10;
const int INF=2000000000;
const int N=100005;

int a[]={31,37,41,43,47};

i64 C[105][105],B[105];

int n;

i64 exGcd(i64 a,i64 b,i64 &x,i64 &y)
{
    i64 t,d;
    if(!b)
    {
        x=1;
        y=0;
        return a;
    }
    d=exGcd(b,a%b,x,y);
    t=x;
    x=y;
    y=t-a/b*y;
    return d;
}

int modular1(i64 a[],i64 m[],int k)
{
    i64 d,t,c,x,y,i;

for(i=2;i<=k;i++)
    {
        d=exGcd(m[1],m[i],x,y);
        c=a[i]-a[1];
        if(c%d) return 0;
        t=m[i]/d;
        x=(c/d*x%t+t)%t;
        a[1]=m[1]*x+a[1];
        m[1]=m[1]*m[i]/d;
    }
    return 1;
}

int M,mod;

struct Matrix
{
    i64 a[50][50];
    
    void init(int x)
    {
        clr(a,0);
        int i;
        if(x) FOR0(i,50) a[i][i]=1;
    }
    
    Matrix operator*(Matrix p)
    {
        Matrix ans;
        ans.init(0);
        int i,j,k;
        FOR0(k,M) FOR0(i,M) FOR0(j,M)
        {
            ans.a[i][j]+=a[i][k]*p.a[k][j]%mod;
            ans.a[i][j]%=mod;
        }
        return ans;
    }
    
    Matrix pow(int n)
    {
        Matrix ans,p=*this;
        ans.init(1);
        while(n)
        {
            if(n&1) ans=ans*p;
            p=p*p;
            n>>=1;
        }
        return ans;
    }
};

Matrix q;

i64 cal(i64 p)
{
    int i,j;
    for(i=1;i<=p;i++)
    {
        C[i][0]=C[i][i]=1;
        for(j=1;j<i;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%p;
    }
    B[0]=B[1]=1;
    for(i=2;i<=p;i++)
    {
        B[i]=0;
        for(j=0;j<i;j++) B[i]=(B[i]+C[i-1][j]*B[j]%p)%p;
    }
    if(n<=p) return B[n];
    
    q.init(0); M=p; mod=p;
    for(i=1;i<p;i++) q.a[i][i-1]=1;
    q.a[0][p-1]=q.a[1][p-1]=1;
    q=q.pow(n-p+1);
    i64 ans=0;
    FOR0(i,p) ans=(ans+B[i]*q.a[i][p-1])%p;
    return ans;
}

int main()
{
    rush()
    {
        RD(n);
        i64 A[10],M[10],i;
        FOR0(i,5) M[i+1]=a[i],A[i+1]=cal(a[i]);
        modular1(A,M,5);
        printf("%I64d\n",A[1]);
    }
    return 0;
}