关闭

poj 1150

177人阅读 评论(0) 收藏 举报
分类:

求最后一个非0位

题目描述:

超大组合数:求超大组合数P(n, m)的最后一个非零位。

题解:

n!/m!的最后一位.可以看出来有几个2和几个5,搞出来有几个10.然后再除以他们之后%10.发现阶乘直接%10不行,因为10是质合数.因此可能这样做:先拆成%5和%2但是发现除以10的x次方之后的数字不好写成形式.于是换这样的方法:只需要是个位,因此只看个位:先看2和5的多少.如果5多于2,一定是5.如果2等于5.那么剩下的就是全部刨去2和5之后剩下的个位数.剩下的3,7,9看结尾的有几个就好了.而如果2多于5,那么结果乘以2就好.之后就是具体怎么算个位的数.对于n,先看奇数,偶数不能处理,因此递归到之后n/2.奇数中的5的倍数,不能处理,因此递归到处理奇数的n/5.

重点:

首先是思路:除去5和2的个位数的统计.
其次是统计:首先递归处理n.然后对n分奇偶.之后对于奇数,在对5进行一次递归

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <ctype.h>
#include <limits.h>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#define CLR(a) memset(a, 0, sizeof(a))
#define REP(i, a, b) for(int i = a;i < b;i++)
#define REP_D(i, a, b) for(int i = a;i <= b;i++)

typedef long long ll;

using namespace std;

int n, m;
int cal_odd(int n, int a)//计算奇数.
{
    if(n==0)
    {
        return 0;
    }
    int ans = 0;
    ans = n/10;
    int t = n%10;
    if(t >= a)
    {
        ans++;
    }
    ans += cal_odd(n/5, a);//重点.计算奇数5.那么递归计算奇数5
    return ans;
}
int cal_n(int n, int a)
{
    if(n==0)
    {
        return 0;
    }
    int ans;
    ans = cal_n(n/2, a) + cal_odd(n, a);//递归
    return ans;
}
int cal_n_2_5(int n, int a)//正常统计
{
    int res = 0;
    while(n!=0)
    {
        res += n/a;
        n /= a;
    }
    return res;
}

int mod(int x, int m)
{
    return (x-1)%m + 1;
}

void solve()
{
    int e3, e7, e9;
    int e5 = cal_n_2_5(n, 5)-cal_n_2_5(m,5),e2=cal_n_2_5(n, 2)-cal_n_2_5(m,2);
    if(e5 > e2)
    {
        printf("5\n");
    }
    else
    {
        e3 = cal_n(n, 3)-cal_n(m, 3);
        e7 = cal_n(n, 7)-cal_n(m, 7);
        e9 = cal_n(n, 9)-cal_n(m, 9);
        e3 = mod(e3, 4);
        e7 = mod(e7, 4);
        e9 = mod(e9, 2);
        int res = 1;
        while(e3!=0)
        {
            res *= 3;
            e3--;
        }
        res %= 10;
        while(e7!=0)
        {
            res *= 7;
            e7--;
        }
        res %= 10;
        while(e9!=0)
        {
            res *= 9;
            e9--;
        }
        res %= 10;
        if(e2 > e5)
        {
            e2 -= e5;
            e2 = (e2 - 1)%4 + 1;
            //e2 %= 4;
            while(e2!=0)
            {
                res *= 2;
                e2--;
            }
        }
        res %= 10;
        printf("%d\n", res%10);
    }
}

int main()
{
    //freopen("1Ain.txt", "r", stdin);
    //freopen("1Aout.txt", "w", stdout);
    while(scanf("%d%d", &n, &m) != EOF)
    {
        m = n - m;
        solve();
    }
    return 0;
}
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:43037次
    • 积分:2402
    • 等级:
    • 排名:第15422名
    • 原创:206篇
    • 转载:0篇
    • 译文:0篇
    • 评论:1条
    最新评论