nowcoder 115 H 小P的数学问题

题目链接

题目:

题目描述
晚上,小P喜欢在寝室里一个个静静的学习或者思考,享受自由自在的单身生活。
他总是能从所学的知识散发出奇妙的思维。
今天他想到了一个简单的阶乘问题,
0!= 1
1!= 1
2!= 1 * 2 = 2
3!= 1 * 2 * 3 = 6
4!= 1 * 2 * 3 *4 = 24
5!= 1 * 2 * 3 *4 * 5 = 120


如果 n=1000000000,那么n的阶乘会是多少呢,小P当然知道啦,那么你知道吗?
输入描述:

第一行输入一个整数T(表示样例个数)
接下来T组样例
每组样例一行,输入一个整数N(0<=N<=1000000000)

输出描述:

输出T行
每一行输出N的阶乘 N!(由于这个数比较大,所以只要输出其对1000000007取膜的结果即可)

示例1

输入

2
0
1000000000

输出

1
698611116


参考了下面这篇文章

np问题(大数阶乘取模)

分析:

求阶乘很容易,但是1000000000太大了,不太可能直接在1秒算出来,所以采取打表的方法来做。
思路:先在本地算出1~1000000000的所有阶乘,把结果放到数组中。为了控制打表出来的数组的长度,只每隔10000000就输出一次结果,也就是间隔地取100个数放到数组中——这样就相当于把所有的数字分成了[1~10000000], [10000001~20000000], …, [990000001,1000000000] 一共一百个区间,每个区间记录的是左端点-1的阶乘,接下来要计算任何 n! 只要在 n 对应的区间的基础上继续计算阶乘就行了。对每个n,它对应的区间其实刚好就是 n/10000000 ,在这个基础上再计算 n 次就行了。显然最多计算10000000次(区间的宽度)就可以了,所以答案是可行的。

代码:

#include<stdio.h>

#define mod 1000000007
//打表的代码,存到了文件里面
//int main() {
//
//  unsigned long long cnt=1;
//  freopen("in.txt", "w", stdout);
//
//  for (unsigned long long i = 1; i <= 1000000000; ++i) {
//      cnt = cnt*i % mod;
//      if (i % 10000000 == 0)printf("%llu,", cnt);
//  }
//}

//从文件拷贝到代码中的,记得第一个区间[1,10000000]记录的是1哦
int a[] = {1,682498929,491101308,76479948,723816384,67347853,27368307,625544428,199888908,888050723,927880474,281863274,661224977,623534362,970055531,261384175,195888993,66404266,547665832,109838563,933245637,724691727,368925948,268838846,136026497,112390913,135498044,217544623,419363534,500780548,668123525,128487469,30977140,522049725,309058615,386027524,189239124,148528617,940567523,917084264,429277690,996164327,358655417,568392357,780072518,462639908,275105629,909210595,99199382,703397904,733333339,97830135,608823837,256141983,141827977,696628828,637939935,811575797,848924691,131772368,724464507,272814771,326159309,456152084,903466878,92255682,769795511,373745190,606241871,825871994,957939114,435887178,852304035,663307737,375297772,217598709,624148346,671734977,624500515,748510389,203191898,423951674,629786193,672850561,814362881,823845496,116667533,256473217,627655552,245795606,586445753,172114298,193781724,778983779,83868974,315103615,965785236,492741665,377329025,847549272,698611116};

//使用长整形防止在乘法的时候溢出
typedef unsigned long long ll;
int main() {
    int t;
    scanf("%d", &t);
    //统一要参与乘法的变量的类型
    ll n, i,ans,block= 10000000;//区间长度
    while (t--)
    {
        scanf("%llu", &n);
        ans = a[n / block];
        for (i = 1; i <= (n % block); ++i) {//在基础上继续做阶乘
            ans = ans*(i+n/block*block)%mod;
        }
        printf("%llu\n", ans);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值