• Topcoder SRM 569 Div1


    Topcoder SRM 569 Div1 - MegaFactorial (矩阵)

    首先是对于末尾0个数的处理,设最后得到的数中包含(i)的指数为(F(i))

    对于(B=2,3,5,7)的情况,可以直接计算答案(sum_{i=1}sum_{j=1}F(jcdot B^i))

    对于(B)为质因子组合的情况,即(B=6(2 imes 3),10(2 imes 5)),因为(F(i))实际有单调性,可以直接取较大的质因子

    对于(B)为质因子次方的情况,即(B=2^2,2^3,3^2)的情况,设(B=p^k)则答案可以表示为

    $egin{aligned} lfloor frac{sum_{i=1}sum_{j=1}F(jcdot p^i)}{k} floor end{aligned} $

    由于要取模,实际上要做一点魔改,设模数为(m),答案可以表示为(c=ak+b)的形式,这个式子求出的是(a)

    (lfloor frac{(ak+b)mod km }{k} floor =a+lfloor frac{(bmod km)}{k} floor =a)

    由于(kleq 3),扩大模数后可以用unsigned int 存

    下面考虑用矩阵求解上式

    (nk!)(下面用(f(n,k))表示)这个东西可以看作从(n)向下的一个递推式

    因此考虑以(k)为矩阵元素,求出每个(f(n,k))被调用的次数

    注意这样递推就是反向的了

    递推的转移式子是(f(n,k) ightarrow f(n,k-1),f(n-1,k)),其中(f(n,k-1))的转移需要在层内完成

    据此构造矩阵即可,注意(f(n,0))不能向(f(n-1,0))转移

    考虑对于(sum_{i=1}sum_{j=1}F(jcdot B^i))的每个(i)求解,一共有(frac{n}{B^i})(j),每个(j)出现的递推层数为等差数列

    即$nmod B^i,nmod Bi+Bi,nmod B^i +2 cdot B^icdots $

    我们要求的其实是每一层的(f(i,0)),所以考虑求出每次(B^i)层的转移矩阵

    然后是依次累和,把矩阵的转移中(0 ightarrow 0)的转移赋为1即可做到

    tips:首项是(nmod B^i)

    一共有(log _Bn)种不同的(i),因此复杂度为(O(log_Bnlog_2 ncdot k^3))

    当然更优的做法,咕咕咕

    #include<bits/stdc++.h>
    using namespace std;
    
    #define reg register
    typedef long long ll;
    typedef unsigned int U;
    #define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
    #define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)
    
    #define pb push_back
    template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
    template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }
    
    char IO;
    int rd(){
    	int s=0;
    	int f=0;
    	while(!isdigit(IO=getchar())) if(IO=='-') f=1;
    	do s=(s<<1)+(s<<3)+(IO^'0');
    	while(isdigit(IO=getchar()));
    	return f?-s:s;
    }
    
    const int N=20;
    
    
    int n,d;
    U P=1e9+9;
    struct Mat{
    	U a[N][N];
    	Mat(){ memset(a,0,sizeof a);} 
    	void One(){ rep(i,0,d) a[i][i]=1; }
    	U* operator [] (int x){ return a[x]; }
    	Mat operator * (const Mat &x) const {
    		Mat res;
    		rep(i,0,d) rep(j,0,d) rep(k,0,d) res.a[i][k]=(res.a[i][k]+1ll*a[i][j]*x.a[j][k])%P;
    		return res;
    	}
    	void Show(){
    		rep(i,0,d) { rep(j,0,d) printf("%d ",a[i][j]); puts(""); }
    	}
    } A,B,C;
    
    Mat qpow(Mat x,int k){
    	Mat res; res.One();
    	for(;k;k>>=1,x=x*x) if(k&1) res=res*x;
    	return res;
    }
    int Factor(int &x) {
    	int p=-1,c=0;
    	rep(i,2,x) if(x%i==0) {
    		while(x%i==0) c++,x/=i;
    		p=i;
    		break;
    	}
    	return x=p,c;
    }
    
    class MegaFactorial {
    	public:
    		int countTrailingZeros(int N, int K, int b) {
    			A=Mat(),n=N,d=K;
    
    			if(b==10) b=5;
    			if(b==6) b=3;
    			int t=Factor(b);
    			P*=t;
    
    			drep(i,d,0) {
    				A[i][i]=1;
    				rep(j,0,d) A[j][i]+=A[j][i+1];
    			}
    			A[0][0]=0;
    			ll ans=0;
    			for(ll i=b;i<=n;i*=b) {
    				B=qpow(A,i); B[0][0]=1;
    				Mat res=qpow(A,n%i)*qpow(B,n/i-1);
    				rep(i,0,d) (ans+=res[i][0])%=P;
    			}
    			P/=t,ans/=t;
    
    			return ans;
    		}
    };
    
    
    
  • 相关阅读:
    Linux之Permission denied没有权限
    soapUI的简单使用(webservice接口功能测试)
    jmeter学习(二),如何安装jmeter?
    loadrunner检查点设置失败,日志中SaveCount无法被正常统计出来
    loadrunner破解出现“license security violation,Operation is not allowed”的错误提示
    安装LoadRunner11报缺少vc2005_sp1_with_atl_fix_redist的错误
    IOS测试,打不开要测试的APP怎么办?设置信任
    Jmeter的好搭档Badboy的安装与简单使用
    映射网络驱动器会自动断开的解决方法
    oracle中如何修改用户名和密码
  • 原文地址:https://www.cnblogs.com/chasedeath/p/13618510.html
Copyright © 2020-2023  润新知