今天看完了离散关于求模的那一章然后顿时想到了这个的解法…ACM大神勿喷…(我不是竞赛的……)
/* Author: Latyas Jilin University 思路:防止5的影响,将n!分解为2^a*5^b*c1c2c3c4...cn*/#include#include int TWO = 0;int FIVE = 0;int Run(int);int fuckTwoFive(int); int CongruenceExp(int base,int exp,int m); //同余幂算法int main(){ int temp = 1; while(scanf("%d",&temp)) { printf("%d -> %d\n",temp,Run(temp)); TWO = FIVE = 0; } system("pause"); return 0;}int Run(int input){ if(input == 1 || input == 0) return 1; int result = 1; for(int i = 1;i<=input;i++) { result *= fuckTwoFive(i)%10; //根据求模公式的变形防止数值膨胀 result %= 10; } TWO -= FIVE; /* 算2的n次幂模10的结果有两个方法 1.2^n % 10的结果是循环出现的,注释掉的代码即这种方法,有特殊性 2.更一般的算法是2^t 将t展开为二进制,即用同余幂算法求模 这里用这个方法,因为代码看上去更简洁了 =w= */ int Tworesult = 1; /* static const int map2[5] = {1,2,4,8,6}; for(int i = 0;i<=TWO/4;i++) { if((Tworesult *= 6) > 10) Tworesult %= 10; } Tworesult = (Tworesult*map2[TWO%4])%10; */ Tworesult = CongruenceExp(2,TWO,10); //同余幂求模 result = (result*Tworesult)%10; return result;}int fuckTwoFive(int input){ if(input%5 == 0) { while(1) { if(input%5 != 0) break; input /= 5; FIVE++; } } if(input%2 == 0) { while(1) { if(input%2 != 0) break; input /= 2; TWO++; } } return input;}int CongruenceExp(int base,int exp,int m){ int k = 0; int temp = exp; for(int i = 0 ;;i++) { if((temp/=2) == 0) { k = i; break; } } int x = 1; int power = base%m; for(int i = 0;i<=k;i++) { if(exp&(1<