zoukankan      html  css  js  c++  java
  • poj1150

    题意:给出n,m,求n中取m个的排列数抛掉末尾的0后的最后一位。

    分析:题目可以转化为求一段连续数列的乘积的最后非0位。乘积的末尾之所以会有0,是因为数字中有包含2和5的倍数,2和5这两个质因子组成了0。我们先将所有2和5质因子去除,求其余数字乘积的最小位。我们将2的倍数全部取出,把每个数字除以2,这样就得到了一个小一些的连续数列,这样就转化为了一个子问题,用相同方法求其最小非0位即可,具体方法稍后讲。原连续数列中去除2的倍数的同时5的偶数倍也被去除了,还剩下所有的奇数,对于这个奇数数列我们将5的奇数倍(以5结尾的数字)取出,对于这些数字除以5之后得到了一个较小的连续奇数列,转化为了一个子问题。此时原连续数列中还剩下以1,3,7,9结尾的数字,这些数字用找循环节的方式求乘积最小位即可。到目前为止,对于连续数列的求解被我们分为3部分,一部分直接计算(1379结尾的),另外两部分转化为子问题,一个子问题是求连续数列的乘积最小非0位(2的倍数),另一个子问题是求连续奇数列的最小非0位(以5结尾的)。对于奇数列的求解,我们把数列分为3部分,一部分直接求解(1379结尾的),另一部分转化为子问题(以5结尾的)。这样递归下去即可求出原连续数列乘积抛掉质因子2和5之后的最小位。我们在递归过程中可以记录被去掉的2和5的个数。现在我们试着将这些2和5乘回去。如果5比2多,那么原数列最小非0位是5。如果2比5多,那么相当于除去2和5的乘积最小位乘以比5多出来的那些2,同样可以用找循环节的方式求解。

    View Code
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    
    int s, e;
    int count_two, count_five;
    
    int get_digit(int s, int e)
    {
        int s1 = s / 10 * 10 + 10;
        int e1 = e / 10 * 10;
        int ret = 1;
        if (e1 <= s1)
        {
            for (int i = s; i <= e; i++)
                if ((i & 1) && (i % 5 != 0))
                    ret = ret * (i % 10) % 10;
            return ret;
        }
        ret = (e1 - s1) / 10 % 2 * 8 + 1;
        for (int i = s; i < s1; i++)
            if ((i & 1) && (i % 5 != 0))
                ret = ret * (i % 10) % 10;
        for (int i = e1 + 1; i <= e; i++)
            if ((i & 1) && (i % 5 != 0))
                ret = ret * (i % 10) % 10;
        return ret;
    }
    
    int cal_odd(int s, int e)
    {
        if (s > e)
            return 1;
        int ret = get_digit(s, e);
        int s1 = s;
        while (s1 % 10 != 5)
            s1++;
        int e1 = e;
        while (e1 > 0 && e1 % 10 != 5)
            e1--;
        if (e1 < s1)
            return ret;
        s1 /= 5;
        e1 /= 5;
        ret = ret * cal_odd(s1, e1) % 10;
        count_five += (e1 - s1) / 2 + 1;
        return ret;
    }
    
    int cal(int s, int e)
    {
        if (s > e)
            return 1;
        int ret = cal((s + 1) / 2, e / 2) % 10;
        count_two += e / 2 - (s + 1) / 2 + 1;
        ret = ret * cal_odd(s, e) % 10;
        return ret;
    }
    
    void test(int s, int e)
    {
        long long a = 1;
        for (int i = s; i <= e; i++)
        {
            a *= i;
            while (a % 10 == 0)
                a /= 10;
        }
        printf("%lld", a % 10);
    }
    
    int main()
    {
        //freopen("t.txt", "r", stdin);
        while (~scanf("%d%d", &e, &s))
        {
            s = e - s + 1;
    //        test(s, e);
            count_two = 0;
            count_five = 0;
            int ans = cal(s, e);
            if (count_five > count_two)
            {
                puts("5");
                continue;
            }
            int temp = count_two - count_five;
            if (temp == 0)
            {
                printf("%d\n", ans);
                continue;
            }
            temp--;
            ans = ans * 2 % 10;
            for (int i = 0; i < temp % 4; i++)
                ans = ans * 2 % 10;
            printf("%d\n", ans);
        }
        return 0;
    }
  • 相关阅读:
    浅析Python中bytes和str区别
    Python面对对象相关知识总结
    Django实现微信公众号简单自动回复
    阿里云部署django实现公网访问
    JDBC学习笔记(1)——JDBC概述
    Java单元测试初体验(JUnit4)
    Java设计模式系列之动态代理模式(转载)
    Java设计模式系列之责任链模式
    Java设计模式系列之观察者模式
    局部内部类和匿名内部类的对比
  • 原文地址:https://www.cnblogs.com/rainydays/p/2769828.html
Copyright © 2011-2022 走看看