P1951: [Sdoi2010]古代猪文
呜啊啊啊啊,选错了题,原以为很简单的优化+剪枝就能过结果牵扯到了一堆数论知识。我的错,贴上我的代码(已经尽量优化了)
1 const maxn=999911659; 2 var n,g,i,j,ans:longint; 3 tem:int64; 4 function pow(g,x:longint):longint; 5 var 6 now,tem,i,t:int64; 7 begin 8 tem:=1; now:=g; 9 if g=1 then exit(1); 10 while now<maxn do 11 begin 12 now:=now*now; 13 tem:=tem*2; 14 end; 15 now:=now mod maxn; 16 if (now=0) and (x div tem>=1) then exit(0); 17 if x div tem>=1 then t:=pow(now,x div tem) 18 else t:=1; 19 now:=g; x:=x-tem*(x div tem); 20 while x<>0 do 21 begin 22 if (x mod 2)=1 then begin 23 t:=(t*now) mod maxn; 24 end; 25 now:=(now*now) mod maxn; 26 x:=x div 2; 27 end; 28 exit(t mod maxn); 29 end; 30 function c(x:longint):longint; 31 var i:longint; 32 tem:int64; 33 begin 34 tem:=g; 35 for i:=1 to x do 36 tem:=pow(tem,n-i+1) mod maxn; 37 for i:=1 to x do tem:=trunc(exp(ln(tem)/i)); 38 exit(tem); 39 end; 40 begin 41 readln(n,g); 42 tem:=1; 43 for i:=1 to trunc(sqrt(n)) do 44 if n mod i=0 then 45 begin 46 if i*i<>n then tem:=tem*((c(i) mod maxn)*(c(n div i) mod maxn) mod maxn) mod maxn 47 else tem:=(tem*c(i)) mod maxn; 48 end; 49 writeln(tem mod maxn); 50 end.
然而正确的是。。
#include <cstring> #include <iostream> #include <cmath> #include <algorithm> #include <cstdio> using namespace std; #define maxn 35620 typedef long long LL; #define MOD 999911659 #define M 999911658 LL w[4]={2,3,4679,35617}; LL a[4]; LL fac[4][maxn]; LL Pow(LL a,LL b,LL mod)//快速幂 { LL ans=1; while(b) { if(b&1) ans=(ans*a)%mod; a=(a*a)%mod; b >>= 1; } return ans; } void init()//预处理阶乘 { for(int i=0;i<4;i++) { fac[i][0]=1; for(int j=1;j<=w[i];j++) { fac[i][j]=(fac[i][j-1]*j)%w[i]; } } } /******************************** * 组合数取模用费马小定理 *********************************/ LL C(LL n,LL m,int x)//组合数取模 { if(n < m) return 0; return (fac[x][n] * Pow((fac[x][n-m]*fac[x][m]),w[x]-2,w[x]))%w[x]; } /******************************* * lucas 处理大组合数取模 ********************************/ LL Lucas(LL n,LL m,int x)//lucas定理 { if(m==0) return 1; return (Lucas(n/w[x],m/w[x],x)*C(n%w[x],m%w[x],x))%w[x]; } /**************************** * 扩展欧几里得求乘法逆元 *****************************/ LL exgcd(LL a,LL b,LL &x,LL &y)//乘法逆元 { if(!b){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; } /*************************************************************************************** * 中国剩余定理: * x = b1 % m1 * x = b2 % m2 * x = b3 % m3 * . * gcd(m1,m2,m3,...) = 1; * M = m1 * m2 * m3 *.....; * M1 = m2 * m3 * ...., M2 = m1 * m3 * ...., M3 = m1 * m2 * m4 *....., ......; * M1 * M(-1) = 1 % M ,M2 * M2(-1) = 1 % M; * res = (M1(-1)*b1 + M2(-1)*b2+.....)%M;res即为所求值 * 注:如果取模的值相同:都是m1 那么 bn的值可以相加计算; * 略屌。。。。。。。。。。。。。。 * *****************************************************************************************/ LL CRT()//计算组合数和取模之后的值 { LL i,d,x0,y0,ans=0; for(i = 0;i < 4;i++)//中国剩余定理 { d=M/w[i]; exgcd(d,w[i],x0,y0); ans=(ans+d*x0*a[i])%M; } if(ans <= 0) ans += M; return ans; } int main() { init(); LL g,n; while(cin>>n>>g) { memset(a,0,sizeof(a)); for(int i=1;i*i<=n;i++) { if(n%i==0) { LL tmp=n/i; for(int j=0;j<4;j++) { if(tmp!=i) a[j]=(a[j]+Lucas(n,i,j))%w[j]; a[j]=(a[j]+Lucas(n,tmp,j))%w[j]; } } } cout<<Pow(g%MOD,CRT(),MOD)<<endl; } return 0; }
我就不想多说了=-=
(转载请注明出处:http://www.cnblogs.com/Kalenda/)