hdu 4767 Bell
来源:互联网 发布:初中英语单词大全软件 编辑:程序博客网 时间:2024/05/17 04:27
题目:hdu 4767 Bell
思路:两个公式 B(n+p)%p=(B(n)+B(n+1))%p B(p^m+n)%p=(m*B(n)+B(n+1))%p
首先明确的是,对于取模数,质因数分解 ,直接套用模板了。
#include <cstring>#include <iostream>#include <cmath>#include <algorithm>#include <cstdlib>#include <cstdio>#include <map>using namespace std;#define Times 10typedef long long LL;map<LL,int>mp;LL random(LL n){ return LL ((double)rand()/RAND_MAX*n+0.5);}//避免出现了相乘取余前造成的溢出LL multi(LL a,LL b,LL mod){ LL ans=0; while(b) { if(b&1) { b--; ans=(ans+a)%mod; } else { b/=2; a=(a+a)%mod; } } return ans;}LL Pow(LL a,LL b,LL mod){ LL ans=1; while(b) { if(b&1) { b--; ans=multi(ans,a,mod); } else { b/=2; a=multi(a,a,mod); } } return ans;}// 二次探测找到一个不是x=1或者x=p-1的解就一定不是素数bool witness(LL a,LL n){ LL d=n-1; while(!(d&1))//幂是偶数时有探测的必要 d>>=1; LL t=Pow(a,d,n); while(d!=n-1 && t!=1 && t!=n-1)//如果存在一个非1或非p-1的解,就不是素数 { t=multi(t,t,n); d<<=1; } return t==n-1 || d&1 ;}bool miller_rabin(LL n){ if(n==2) return true; if(n<2 || !(n&1)) return false; for(int i=1;i<=Times;i++) { LL a=random(n-2)+1; if(!witness(a,n)) return false; } return true;}LL gcd(LL a,LL b){ if(b==0) return a; return gcd(b,a%b);}LL pollard_rho(LL n,int c){ LL x,y,d,i=1,k=2; x=random(n-2)+1; y=x; while(1) { i++; x=(multi(x,x,n)+c)%n; d=gcd(y-x,n); if(1<d && d<n) return d; if(y==x) return n; if(i==k) { y=x; k<<=1; } }}void find(LL n,LL c){ if(n==1) return ; if(miller_rabin(n)) { mp[n]++; return ; } LL p=n; while(p>=n) p=pollard_rho(p,c--); find(p,c); find(n/p,c);}void Print(LL x,int num){ while(num--) printf("%I64d ",x);}int main(){ long long p=95041567; mp.clear(); find(p,20131001); map<LL,int>::iterator it=mp.begin(); for(;it!=mp.end();it++) Print(it->first,it->second); printf("\n"); return 0;}
取模数可以质因数分解为 31*37*41*43*47,肯定是分成五个,然后用中国剩余定理合并的。
开始做的时候,用的是第二个公式,结果发现,递归层数太多,会超时。
// TLE 代码#include <cstring>#include <iostream>#include <cmath>#include <algorithm>#include <cstdio>using namespace std;#pragma comment(linker, "/STACK:102400000,102400000")typedef __int64 LL;LL w[5]={31,37,41,43,47};LL a[5]={0,0,0,0,0};LL MOD = 95041567 ;LL Bell[50][5];LL C[50][50][5];LL exgcd(LL a,LL b,LL &x,LL &y){ if(b==0) { x=1; y=0; return a; } LL ans=exgcd(b,a%b,x,y); LL t=x; x=y; y=t-a/b*y; return ans;}LL CRT(int r){ LL M=MOD; LL i,d,x0,y0,ans=0; for(int i=0;i<r;i++) { d=M/w[i]; exgcd(d,w[i],x0,y0); ans=(ans+d*x0*a[i])%M; } while(ans<=0) ans+=M; return ans;}void init(){ memset(C,0,sizeof(C)); for(int k=0;k<5;k++) // C[i][j][k] 表示C(i,j)%w[k] { C[0][0][k]=1; for(int i=0;i<50;i++) { C[i][0][k]=C[i][i][k]=1; for(int j=1;j<i;j++) C[i][j][k]=(C[i-1][j][k]+C[i-1][j-1][k])%w[k]; } } // 预处理出前50项分别取模的大小 for(int k=0;k<5;k++) { Bell[0][k]=1; for(int i=1;i<50;i++) //复杂度10^3左右 { Bell[i][k]=0; for(int j=0;j<i;j++) Bell[i][k]=(Bell[i][k]+Bell[j][k]*C[i-1][j][k]%w[k])%w[k]; } }}LL tmp_Bell(LL n,int p) //返回 Bell[n][p]的值{ if(n<50) return Bell[n][p]; LL cnt=1; int mi=0; while(cnt*w[p]<=n) { cnt*=w[p]; mi++; } n-=cnt; return (mi*tmp_Bell(n,p)%w[p]+tmp_Bell(n+1,p))%w[p];}LL BellNumber(LL n){ for(int i=0;i<5;i++) { a[i]=tmp_Bell(n,i); } return CRT(5);}int main(){ init(); LL n; int t; scanf("%d",&t); while(t--) { scanf("%I64d",&n); printf("%I64d\n",BellNumber(n)%MOD); } return 0;}
上面的代码,很容易就卡死了,所以还是得看看第一个公式。
对于第一个公式,我们可以构造一个大小为当前p*p的矩阵。
构造矩阵后,很快就可以得到分别对各种p的取模值,然后用中国剩余定理合并。
详见代码。
#include <cstring>#include <iostream>#include <cmath>#include <algorithm>#include <cstdio>using namespace std;#pragma comment(linker, "/STACK:102400000,102400000")typedef __int64 LL;LL w[5]={31,37,41,43,47};LL a[5]={0,0,0,0,0};LL MOD = 95041567 ;LL Bell[50][5];LL C[50][50][5];struct Matrix{ LL m[50][50];}E,D;Matrix Multi(Matrix A,Matrix B,int m,int n,int r,int p){ Matrix ans; for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) { ans.m[i][j]=0; for(int k=1;k<=r;k++) ans.m[i][j]=(ans.m[i][j]+A.m[i][k]*B.m[k][j])%w[p]; } return ans;}Matrix Pow(Matrix A,LL k,int n,int p){ Matrix ans=E; while(k) { if(k&1) { k--; ans=Multi(ans,A,n,n,n,p); } else { k/=2; A=Multi(A,A,n,n,n,p); } } return ans;}LL exgcd(LL a,LL b,LL &x,LL &y){ if(b==0) { x=1; y=0; return a; } LL ans=exgcd(b,a%b,x,y); LL t=x; x=y; y=t-a/b*y; return ans;}LL CRT(int r){ LL M=MOD; LL i,d,x0,y0,ans=0; for(int i=0;i<r;i++) { d=M/w[i]; exgcd(d,w[i],x0,y0); ans=(ans+d*x0*a[i])%M; } while(ans<=0) ans+=M; return ans;}void init(){ for(int i=1;i<50;i++) for(int j=1;j<50;j++) E.m[i][j]=(i==j); memset(C,0,sizeof(C)); for(int k=0;k<5;k++) // C[i][j][k] 表示C(i,j)%w[k] { C[0][0][k]=1; for(int i=0;i<50;i++) { C[i][0][k]=C[i][i][k]=1; for(int j=1;j<i;j++) C[i][j][k]=(C[i-1][j][k]+C[i-1][j-1][k])%w[k]; } } // 预处理出前50项分别取模的大小 for(int k=0;k<5;k++) { Bell[0][k]=1; for(int i=1;i<50;i++) //复杂度10^3左右 { Bell[i][k]=0; for(int j=0;j<i;j++) Bell[i][k]=(Bell[i][k]+Bell[j][k]*C[i-1][j][k]%w[k])%w[k]; } }}LL tmp_Bell(LL n,int p) //返回 Bell[n][p]的值{ if(n<50) return Bell[n][p]; Matrix tmp; memset(tmp.m,0,sizeof(tmp.m)); for(int i=1;i<w[p];i++) tmp.m[i][i]=1,tmp.m[i][i+1]=1; tmp.m[w[p]][w[p]]=1; tmp.m[w[p]][1]=1; tmp.m[w[p]][2]=1; LL cnt=n/w[p]; n-=w[p]*cnt; Matrix ans; for(int i=1;i<=w[p];i++) ans.m[i][1]=Bell[i][p]; ans=Multi(Pow(tmp,cnt,w[p],p),ans,w[p],1,w[p],p); return ans.m[n][1];}LL BellNumber(LL n){ for(int i=0;i<5;i++) { a[i]=tmp_Bell(n,i); } return CRT(5);}int main(){ init(); LL n; int t; scanf("%d",&t); while(t--) { scanf("%I64d",&n); printf("%I64d\n",BellNumber(n)%MOD); } return 0;}
- hdu 4767 Bell
- hdu 4767 Bell
- hdu 4767 Bell
- Bell - HDU 4767 贝尔数
- Bell HDU
- HDU 4767 Bell (中国剩余定理)
- HDU 4767 Bell (中国剩余定理)
- HDU 4767 Bell(CRT+矩阵)
- [Bell数] HDU 4767 Bell & BZOJ 3501 PA2008 Cliquers Strike Back
- hdu 4767 bell 中国剩余定理+矩阵快速幂
- hdu 一卡通大冒险[Bell数]
- HDU 4767 Bell (贝尔数 中国剩余定理 构造矩阵) ★ ★
- [bell&stirling]HDU 2512 一卡通大冒险
- HDUOJ 4767 Bell 长春网络赛1009
- hdoj 4767 Bell 【矩阵快速幂 + CRT】
- Bell数
- Bell数
- bell数
- 梦想的启航,那些年,那些书
- 【心情日记】从这里开始吧
- 如何在xmapp上搭建dvwa
- 手机连接wifi 显示“正在获取IP”解决方法
- 阿里巴巴笔试题
- hdu 4767 Bell
- Opengl Coordinate System
- 【LeetCode】Binary Tree Level Order Traversal--(二叉树层序遍历)
- 基于物品的协作性过滤推荐系统(为用户推荐影片)
- 2014阿里巴巴校园招聘笔试
- 顺序表的删除2
- 字符数组与字符串分析
- java内存结构探析
- 个税改革,个税起征点调整与计算