USACO section 3.2 Factorials(dp)

54 篇文章 0 订阅
53 篇文章 0 订阅
Factorials

The factorial of an integer N, written N!, is the product of all the integers from 1 through N inclusive. The factorial quickly becomes very large: 13! is too large to store in a 32-bit integer on most computers, and 70! is too large for most floating-point variables. Your task is to find the rightmost non-zero digit of n!. For example, 5! = 1 * 2 * 3 * 4 * 5 = 120, so the rightmost non-zero digit of 5! is 2. Likewise, 7! = 1 * 2 * 3 * 4 * 5 * 6 * 7 = 5040, so the rightmost non-zero digit of 7! is 4.

PROGRAM NAME: fact4

INPUT FORMAT

A single positive integer N no larger than 4,220.

SAMPLE INPUT (file fact4.in)

7

OUTPUT FORMAT

A single line containing but a single digit: the right most non-zero digit of N! .

SAMPLE OUTPUT (file fact4.out)

4

思路:就是求余,不过要注意2和5的影响,因为没有2和5的影响乘积的个位必不为0,也就是答案,但要是有2和5的话有可能产生多重进位

           如:25*104=2600 进了两位,若直接逐个求余,得到答案将是2,但正确答案是6(随便举个,本题阶乘可能不存在这数据,但可能存在类似的的多重进位)

          因此,我选者将2和5的个数用two,five存下来,而相同的2,5个数会产生进位但不影响余数,除去2,5相同的个数后再乘上前面处理的余数(除去2,5的数)求余就是答案

 

具体代码:

       

/*
ID:nealgav1
LANG:C++
PROG:fact4
*/
#include<fstream>
#include<cstring>
using namespace std;
ifstream cin("fact4.in");
ofstream cout("fact4.out");
const int mm=5200;
const int _two[]={6,2,4,8,6,2,4,8};///乘2的余数
int ans[mm];///除去2,5模10的余数
int main()
{
  int m,mid,two=0,five=0;///记录2,5的总个数
  cin>>m;
  ans[1]=1;mid=2;
  for(int i=2;i<=m;i++)
  {
     mid=i;
     /**除去2,5并记录*/
    while(mid%2==0)
    {
      two++;mid/=2;
    }
    while(mid%5==0)
    {
      five++;mid/=5;
    }
    ans[i]=(ans[i-1]*mid)%10;
  }///乘上2,5取余的答案
   if(two>five)
   {
     two-=five;
     ans[m]=(ans[m]*_two[two%4])%10;
   }
   else if(two<five)
   { 
     ans[m]=(ans[m]*5)%10;
   }
  cout<<ans[m]<<"\n";
}


 

 

 

 

USER: Neal Gavin Gavin [nealgav1]
TASK: fact4
LANG: C++

Compiling...
Compile: OK

Executing...
   Test 1: TEST OK [0.000 secs, 3376 KB]
   Test 2: TEST OK [0.000 secs, 3376 KB]
   Test 3: TEST OK [0.000 secs, 3376 KB]
   Test 4: TEST OK [0.000 secs, 3376 KB]
   Test 5: TEST OK [0.000 secs, 3376 KB]
   Test 6: TEST OK [0.000 secs, 3376 KB]
   Test 7: TEST OK [0.000 secs, 3376 KB]
   Test 8: TEST OK [0.000 secs, 3376 KB]
   Test 9: TEST OK [0.000 secs, 3376 KB]
   Test 10: TEST OK [0.000 secs, 3376 KB]

All tests OK.

YOUR PROGRAM ('fact4') WORKED FIRST TIME! That's fantastic -- and a rare thing. Please accept these special automated congratulations.

Here are the test data inputs:

------- test 1 ----
1
------- test 2 ----
2
------- test 3 ----
7
------- test 4 ----
14
------- test 5 ----
143
------- test 6 ----
645
------- test 7 ----
777
------- test 8 ----
888
------- test 9 ----
999
------- test 10 ----
1000
Keep up the good work!
Factorials
Russ Cox

The insight for this problem is that 0's at the end of a number come from it being divisible by 10, or equivalently, by 2 and 5. Furthermore, there are always more 2s than 5s in a factorial.

To get the last digit of the factorial, we can run a loop to calculate it modulo 10, as long as we don't include any 2s or 5s in the product. Of course, we want to exclude the same number of 2s and 5s, so that all we're really doing is ignoring 10s. So after the loop, we need to multiply in any extra 2s that didn't have 5s to cancel them out.

/*
PROG: fact4
ID: rsc001
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

void
main(void)
{
	FILE *fin, *fout;
	int n2, n5, i, j, n, digit;

	fin = fopen("fact4.in", "r");
	fout = fopen("fact4.out", "w");
	assert(fin != NULL && fout != NULL);

	fscanf(fin, "%d", &n);
	digit = 1;
	n2 = n5 = 0;
	for(i=2; i<=n; i++) {
		j = i;
		while(j%2 == 0) {
			n2++;
			j /= 2;
		}
		while(j%5 == 0) {
			n5++;
			j /= 5;
		}
		digit = (digit * j) % 10;
	}

	for(i=0; i<n2-n5; i++)
		digit = (digit * 2) % 10;

	fprintf(fout, "%d\n", digit);
	exit(0);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值