【HDU刷题】 2000 ~ 2099总结错误【1】【2000~2050】

HDU2015: 偶数求和:

         递推,数学知识。要解决的问题:①。知道一个偶数X的情况下,m个数的序列的平均值。②。某组第一个数为X则,下一组第一个数为多少?

         (①。若知道某偶数为X,m个数根据等差数列求得 sum = m*X + 2 * (m-1)*m / 2   =   m*(X + m -1)  ,平均值  avg = X + m -1.)

         (②。若某个数为X,则m个数为一组的下一组的第一个数 = X + m * X;)

           根据这个公式就很容易求他们的平均值了。先从1到n/m个数求平均值,然后判断m是否能被n整除,若不能则求剩下几个数的平均值。

 

HDU2018: 母牛的故事:

         递推,母牛第 n 年的数量  =  母牛第n-1年的数量  +  母牛第n - 3 年的数量。

          (母牛第n - 1 年的数量 :也即上一年的母牛数量。)

          (母牛第n - 3 年的数量:也即3年前的母牛数量,也即(原来的大母牛 和  刚出生的小母牛的数量【他们3年后就能生小牛了】

 

HDU2019: 数列有序: 

           插入排序。

           我的思路(第一次碰见时):先找到插入的数的位置,然后交换排序。

           大神的思路:交换排序与寻找位置同时进行。

 

HDU2020:绝对值排序:

          写一个比较函数,设置比较规则,比较的是绝对值。

          然后c++用sort调用,c用qsort调用。

           这里详细介绍一下qsort,
           他的原型是qsort(void*base,size_t num,size_t width,int(__cdecl*compare)(const void*,const void*));
           其参数代表1.待排序数组首地址,2,数组中待排序元素的数量,3.各元素的占用空间大小,4.指向函数的指针。

          举例:

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

int cmp(int *a,int *b)
{
    //从小到大排序
    return *a - *b;

    //从大到小排序
    //return *b - *a;
}

int main()
{
    int a[101] = {102,34,76,85,46,98,12,7};
    //排序
    qsort(a,8,sizeof(int),cmp);
    for(int i=0;i<8;i++)
    {
        printf("%d ",a[i]);
    }
}

           cmp函数中,

           fabs(a)-fabs(b);返回的是a和b的绝对值从小到大排序
           fabs(b)-fabs(a);返回的是a和b的绝对值从大到小排序

#include <stdio.h>
#include <math.h>

int cmp(const int *a,const int *b)
{
    return abs(*b) - abs(*a);
}

int main()
{
    int x[101];
    int i;
    int n;
    while(scanf("%d",&n),n)
    {
        for(i=0;i<n;i++)
            scanf("%d",&x[i]);
        qsort(x,n,sizeof(int),cmp);
        for(i = 0;i<n;i++)
            printf("%d%c",x[i],(i!=n-1?' ':'\n'));

    }
}

 

HDU2021:发工资咯:)

          贪心,先发大的,再发小的。如发100的,则需要100张的个数是x/100;剩下的钱是x%100,再对50,10...分别使用相同原理。

 

HDU2022:海选女主角:

         思想简单,设立一个xi,yj,max 三个值。每次输入一个数,就与前边那个数进行比较,如果绝对值比他大就用(xi,yj)记录他的行数和列数,并用max记录他的绝对值值较大者。

        本题还要注意的点: int和long的范围都是-2147483648 ~ 2147483647,因此负数最大值的fabs值求出来是有问题的。因此,可以将数据类型转化为double,最后用  .0f  表示即可。

HDU2023:求平均成绩:

          思路简单,但是我新学了一种格式输出方法

          for(int i=1;i<=n;i++)

                    printf("%d%c",a[i],( i < n)?' ':'\n');   

          不得不说,这个方法牛逼还简单。

HDU2024:C语言合法标识符:

          思路简单,但是总结一些问题。

          1. 字符串读取空格问题。

          scanf("%s",str),读取字符串时碰到空格就会停止,第三个案例会出错。这里要用 gets(str)函数,和 puts( str)函数。

          gets会读取一整行,直到碰到换行符‘ \n '为止,然后不读取换行符,在字符串的后面加上 ‘\0’ 标志。puts(str)直接输出字符串,再自动加一个换行符。

          在c++语言中,可以用getline函数读取一整行。如下图所示:也很方便。

        2.C语言库函数:#include <ctype.h>    里边有 isdigit(str[i])  和  isalpha(str[i] ) 分别判断str[ i ] 这个字符是数字?这个字符是字母?如果是则返回1,否则返回0.

HDU2026:C语言合法标识符:

         第一次submit了好几回都没提交,2月后再一次提交,过了。

         但是还是简单说一下本题解法:  先判断第一位如果是小写,则改成大写,从后边开始如果该字符不是空格且该字符前一位是空格,说明他是首字母,则判断该首字母是否为小写,如果是,ASCII码-32,改成大写。

/*
    HDU2026----01
    Author:wuki
*/

#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main()
{
    char str[105];
    while(gets(str))
    {
        int length = strlen(str);
        if(islower(str[0]))
        {
            str[0] -= 32;
        }
        for(int i=1;i<length;i++)
        {
            if(str[i]!=' ' && str[i-1]==' ')
            {
                if(islower(str[i]))
                    str[i]-= 32;

            }
        }
        printf("%s\n",str);
    }
    return 0;
}

            不过上面写的这个跟运气也有关,下面写一下解决这个问题的一般方法。

            一般解法:问题关键在于找到句子的每一个单词的首字母,如上所述,我们判断前一个字符为空格,本字符为字母即可。同时,为了简单处理第一个字符,我们可以设置第一个字符为空格,然后从第二个字符开始输入和判断,输出时也从第二个字符输出。下面是例子:

#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main()
{
    //默认从第二个字符输出
    char str[105] = " ";
    while(gets(str+1))
    {
        for(int i=1;i<strlen(str);i++)
        {
            if(isalpha(str[i]) && str[i-1]==' ')
                if(islower(str[i]))
                    str[i] -= 32;
        }
        puts(str+1);
    }
    return 0;
}

HDU2028 Lowest Common Multiple Plus :
解释两个概念和用法。

1.GCD(Greatest Common Divisor)最大公约数 。(运用欧几里得算法,也叫辗转相除法)

GCD (a , b) = GCD( b , a%b);

辗转相除法求两个自然数 m 和 n 的最大公约数:

①。r = m % n;

②。循环直到 r = 0

          ②.①   m = r;

          ②.②   n = r;

          ②.①   r = m % n;

③。输出  n ;

#include <stdio.h>
//Greatest Common divisor
//最大公约数
int Gcd(int m,int n)
{
    int r = m%n;
    while(r!=0)
    {
        m = n;
        n = r;
        r = m%n;
    }
    return n;
}
//Lowest Common multiple
//最小公倍数
int Lcm(int m,int n)
{
    return m * n /Gcd(m,n);
}


int main()
{
    int m,n;
    scanf("%d%d",&m,&n);
    printf("Gcd(%d,%d) = %d\n",m,n,Gcd(m,n));
    printf("Lcm(%d,%d) = %d\n",m,n,Lcm(m,n));

    return 0;
}

(补充:2019/6/25 今天我偶然发现一种递归的写法,比循环简单,也很好。代码如下:)

int Gcd(int m,int n)
{
    if(m%n==0)return n;
    else return Gcd(n,m%n);
}

 

2.LCM(Lowest Common Multiple)最小公倍数。 (LCM(x,y) = x * y / GCD(x,y);  )  见上。

3.本题竟然WA了,最后一查教程,原来是求LCM时,x * y 可能发生溢出,改成 x / GCD(x,y) * y 即可。

2029 : Palindromes_easy version:

       两种常用办法

        ①。for(i=0;i<strlen(str)/2;i++)然后判断str[i] 是否等于 str[strlen(str) - i - 1]

        ②。用strrev(string reverse)字符串反转函数,即创建两个字符串,str和str2,先把字符串输入到str中,然后把str内容复制到str2中,(strcpy(str2,str)我原来填反了,显示一堆乱码,还好报错了)。,再比较它们,如果== 0,则是回文串,否则不是。这里给予第二种方法代码。

#include <stdio.h>
#include <string.h>
int main()
{
    int i,n;
    char str[1024];
    char str2[1024];
    while(scanf("%d%*c",&n)!=EOF)
    {
        for(i=1;i<=n;i++)
        {
            gets(str);
            strcpy(str2,str);
            strrev(str2);
            if(strcmp(str,str2))
                puts("no");
            else
                puts("yes");
        }
    }
}

HDU2030: 汉字统计

  涉及到 ” 汉字机内码 “,不太懂,但是做题要点是:①。汉字的ASCII码值占2个字节,②。2个字节都是负的。

则只需要用字符流数据判断他的ASCII值,若为负,则cnt++,最后的cnt值除以2就是汉字的个数。

HDU2032:杨辉三角形

    核心代码:

        memset(a,0,sizeof(a));

        for(i=1;i<=n;i++)
        {
            for(j=1;j<=i;j++)
            {
                if(i==1 || i==j)
                    a[i][j] = 1;
                else a[i][j] = a[i-1][j-1] + a[i-1][j];
            }
        }

HDU2034:人间人爱A-B

       我的思路:用两个for循环判断,外层循环是集合a的数,内层是a与  b的所有元素  进行比较。同时,开辟一个新数组c,如果比较b中所有的元素都没有,则把这个数,存到c当中。。

       错误总结:①。本题还要求从小到大排序。(导致WA了)②。本来用C++思路超级正确但还是WA了,才发现set集合没有s.clear(),也即没有初始化导致的。本来样例通过了,不得不说老师水平确实厉害, 设置的案例确实很难让人想到初始化这个问题。以后一定要注意初始化啊。

        ( 当然还可以用C++里面的set集合啦,set是一个关联容器,它是具有  唯一的且排好序的  元素序列,与红黑树还有关系呢。里面有简单的 s.erase( x )函数,很方便的啦,下面给出C++简易版本的代码,哎,用了STL真是简单的一批)。但是上面的思想需要理解,大神还可以用二分查找等。)

        (C++ 我还是说下简单的思路吧,要不然自己也忘了。设置一个set 集合 s,先把前n个数读入set ,然后后边输入m个数,在每次输入的时候判断这个数 在集合s里面有没有,如果有就删除它。而且由于set是默认排好序的,所以可以直接输出。再说明一点:判断集合里有没有可以用count(x)函数,当然不用写也行,因为s.erase(x)如果没有x它是没有任何效果的)。

#include <iostream>
#include <set>
#include <cstdio>
using namespace std;
int main()
{
    int n,m,t;
    set <int > s;
    set<int >::iterator it;

    while(scanf("%d%d",&n,&m),n+m)
    {
        while(n--)
        {
            scanf("%d",&t);
            s.insert(t);
        }
        while(m--)
        {
            scanf("%d",&t);
            if(s.count(t))s.erase(t);
        }

        for(it=s.begin();it!=s.end();it++)
            printf("%d ",*it);
        printf(s.size()?"\n":"NULL\n");
        s.clear();

    }
    return 0;
}

HDU 2035,1061:涉及到2个概念,分别是“快速幂”,和 ” 取模  “,朴素幂的Time complexity 是O(N),而快速幂是O(N).”取模"涉及到图论知识,当然也可以光了解这个知识:a^b%c = (a%c)^b%c.

(HDU2035用朴素幂完全可以解决)(HDU 1061  因为 N <=1,000,000,000,非常大,所以用快速幂)

他的详细介绍我写到了另一篇文章:https://mp.csdn.net/postedit/89631406,里面介绍详细,大家可以去看看。

下面我附上核心代码。

//求a^b%c
int quick_pow(int a,int b,int c)
{
    int res = 1;
    int base = a%c;
    while(b)
    {
        if(b&1) res = res * base %c;
        base = base * base %c;
        b = b>>1;
    }
    return res;
}

 HDU2036:改革春风吹满:

     逆序 给三个点(x0,y0),(x1,y1),(x2,y2),则这三个点组成的三角形的面积是:(公式)

      0.5 * (   (x0*y1-x1*y0) + (x1*y2-x2*y1) + (x2*y0-x0*y2)   ) 。

  (拓展:其实有n个逆序组成的n边形的面积公式:0.5 * ( (x0*y1-x1*y0) + (x1*y2-x2*y1) + …… + (xn*y0-x0*yn)   )

 

本题的思想如图所示:

也即,把所有的点都和(x0,y0)连接起来,求每个三角形的面积之和即可。 为了方便,我仅给出核心代码:

//逆序 给三个点(x0,y0),(x1,y1),(x2,y2),求他们的面积
double area(int x0,int y0,int x1,int y1,int x2,int y2)
{
    return 0.5*((x0*y1-x1*y0)+(x1*y2-x2*y1)+(x2*y0-x0*y2));
}

HDU2037:今年暑假不AC

        贪心算法的经典例题,我们这样想,怎样选才能看到更多场球赛,我们可以贪婪的想:结束的时间最早,我就可以看更多。该球赛结束后,我们再找一个结束时间早的(核心),且开始时间比原来看球赛的结束时间迟的(这是自然的,想想看)。

        比如本题给的数据:我们先按结束时间进行排序,结束早的排在前面。原理如图:

并给出代码:(不熟悉的话,多敲打几遍就熟悉啦)

#include <iostream>
#include <algorithm>
using namespace std;

struct tv
{
    int b;//开始时间
    int e;//结束时间
    bool operator <(const tv t)
    {
        return e <t.e;//结束早的排在前面
    }

};
struct tv t[105];

int main()
{
    int n;
    int k;  //k标志着当前看的电影
    int cnt;//cnt对电影数量计数
    while(cin >> n,n)
    {
        t[0].e = 0;
        k = 0;
        cnt = 0;
        //Input
        for(int i=1;i<=n;i++)
        {
            cin >> t[i].b >> t[i].e;
        }

        sort(t+1,t+n+1);        //2019.9.2 update

        for(int i=1;i<=n;i++)
        {
            if(t[i].b >=t[k].e)
            {
                k = i;
                cnt++;
            }
        }
        cout << cnt << endl;

    }
    return 0;
}

 HDU2039三角形:

          Output Limit Exceed :  多输入了东西,看看是不是kase多输入了。

          WA:虽然是简单题,但是你考虑三角形也可能是实数了吗?(可惜我就错了。

HDU2040:亲和数:

          1.曾经错了一会,debug发现,我加约数把自己也算上了,如220 284,我的cnt值为504,才想到这个问题,注意身体。

          2.第二次错了,是因为忘了输入kase,结果出错。

   ★     3.网上找到更简单的一个做法,恨不得把代码贴上来,算了我还是贴上来吧,说下思路:只要从1循环到n/2就行啦。不用进行后面的。

#include <stdio.h>

int A(int n)
{
    int i;
    int sum = 0;
    for(i=1;i<=n/2;i++)
    {
        if(n%i==0)sum += i;
    }
    return sum;

}

int main()
{
    int kase;
    int a,b;
    scanf("%d",&kase);
    while(kase--)
    {
        scanf("%d%d",&a,&b);
        puts((A(a)==b && A(b)==a)?"YES":"NO");
    }
    return 0;
}

HDU2041: 超级楼梯

          递归的思想:我们可以这么想。

          从1  ->  2楼,只要1种办法。

          从1  ->  3楼,有2种办法。1->3 ,  1->2->3。

          从1  ->  4楼,有两种途径,即从2->4(从2楼跨两步到达4楼),和3->4(从3楼跨一步到大4楼),而从1楼到2楼到有1种办法,从1楼到3楼有2办法。故加起来有3种办法。

           、、、、、、、、、、、、、、、

下面图解:

                   

那么很容易写出一个递归:

int Fun(int n)
{
    if(n==2)return 1;
    else if(n==3)return 2;
    else if(n>3) return Fun(n-1)+Fun(n-2);
    return 0;
}

HDU2042:不容易系列之二

          我们很容易可以用循环迭代的方式来做这道题。但还有没有其他思路呢:(与HDU2013基本一样)

我们尝试一下用递推把。

首先    F(1) = 4 .   F(2) = (4 - 1)*2 = 6;

           F( n ) = (  F(n-1)  -  1  )  * 2;

=====》   F(n) - 2   =   2 * ( F( n-1 )- 2 ) ;

=====>    F(n)  - 2   =   2^(n-1)  *   (F(1) -1 )  )

=====>   F(n)  -  2   =  2^n;

=====>    F(n)    =   2^n  +  2;

怎么样,是不是很神奇,所以给自己定了个目标,好好学习数学,看来他们说数学是计算机的鼻祖真不是吹的,学好数理化走遍天下都不怕。

printf("%.0f\n",pow(2,n)+2);

HDU2043:密码

         按照题目要求做即可,用到<ctype.h>中的isupper ,islower, isdigit函数

Note:   如果没有给出字符串的长度(本文中是密码的长度),还可以用getchar函数来解决。

#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main()
{
    int i,n;
    char c;
    int flag[4];
    int length,cnt;//cnt记录字的长度,cnt记录满足了几个要求
    scanf("%d%*c",&n);
    while(n--)
    {
        memset(flag,0,sizeof(flag));
        cnt = 0;
        length = 0;

        while((c = getchar())!='\n')
        {
            if(isupper(c))
                flag[0] = 1;
            else if(islower(c))
                flag[1] = 1;
            else if(isdigit(c))
                flag[2] = 1;
            else flag[3] = 1;

            length++;
        }
        //计算满足的条件个数
        for(i=0;i<4;i++)
            if(flag[i])cnt++;
        //判断所有条件是否满足
        if(8<=length && length<=16 && cnt >=3)
            puts("YES");
        else
            puts("NO");
    }
    return 0;
}

HDU2044:一只小蜜蜂

   第一次,竟然超时了。以下是超时代码:

//超时代码

#include <stdio.h>

int f(int x)
{
    if(x==1)return 1;
    else if(x==2) return 2;
    else return f(x-1)+f(x-2);
}

int main()
{
    int kase;
    int a,b;
    scanf("%d",&kase);
    while(kase--)
    {
        scanf("%d%d",&a,&b);
        printf("%d\n",f(b-a));
    }
    return 0;
}
//我测试f(1,43),需要大概2秒,f(1,49)更是半天出不来。严重超时,递归次数太多了。

 错误总结:

1.理解了什么是打表:(自己总结)

打表,通俗理解就是“预处理”的意思,把所有可能的情况都求出来,你要哪一个我直接查表,把表中的结果给你。
通常解决需要重复计算的问题,如求第n项Fibonacci数列,如果用递归,小的数还很快能得出结果,当数较大时,需要重复递归好多次(做无用功),会TLE(时间超时),如HDU2044,用递归很难算出来。打表递推,不会超时。
再比如判断是不是素数,用筛选法时,我把范围内的所有的素数都求出来,是素数为1,否则为0,你要求哪一个,我在对应的表中查表,如果是1,告诉你是1,否则告诉你为0。即提前把所有的结果都求出来,避免重复计算。
希望能给你提供帮助。

2.对很大的数做递归,必定超时,这里打表递推。

3.还要用long long型,因为数据到了后面特别大,int会溢出,成为负值。

#include <stdio.h>
#define ll long long
int main()
{
    int kase;
    int a,b,i;
    scanf("%d",&kase);
    ll array[51];
    array[1] = 1;
    array[2] = 2;
    for(i=3;i<=49;i++)
    {
        array[i] = array[i-1]+array[i-2];
    }
    while(kase--)
    {
        scanf("%d%d",&a,&b);
        printf("%lld\n",array[b-a]);
    }
    return 0;
}

HDU2045:不容易系列之(三)---Lele的RPG难题(这道题要回头看)。

          这道题真是“ 题如其名 ”,理解起来相当不容易,做的也真的不容易。

          看了大神们的指导才明白了一些。

          1.f(1) = 3,f(2) = 6,f(3) = 6.(这三种情况还比较好算出来)

          2. n > 3的时候,考虑两种情况。第一,第n个正确的方格摆设可能是第n-1个正确的方格右边添加一位形成的,这时,只有一种方法。第二,若前n-1项不合法,加一位后合法,则前n-2项合法,第n-1项与第一项相同。这时最后一位添加的颜色就有两种,即两种方法。

当然我喜欢看图说话:

          故可列出地推式
       1. n = 1 时,x  = 3;
       2. n = 2 时,x =  6;
       3. n = 3 时,x =  9;

          f  ( n ) = f ( n - 1 ) + 2 * f ( n - 2) 

下面附上我的代码:

          ★  说之前note下我WA的三个问题:

            1.递归改成递推,先打表(列出所有可能的值)

            2.数据到了最后会非常大,用long long型存储数组。

            3.数组开小了,下回开大点,我开了50,第50个数不能存。

#include<stdio.h>
int main()
{
    int n;
    long long arr[51] = {0,3,6,6};
    for(int i=4;i<=50;i++)
        arr[i] = arr[i-1] + arr[i-2]*2;
    while(scanf("%d",&n)!=EOF)
    {
        printf("%lld\n",arr[n]);
    }
    return 0;
}

 

HDU2046:骨牌铺方格

         依旧打表,但是得注意是怎么来的:

         第n副图是在第n-1副图的右边画一个竖的骨牌,和第n-2副图右边画两个横着的骨牌(不能画竖的了,否则会与上边重复)。

 HDU2047:阿牛的EOF牛肉串:

        上次做这种递推题做的快要吐了,主要是思路不好想,题很难。今天回头做了下看了题解。终于过了。

思路:设置一个D[i][j]的二维数组,D[n][0]代表长度为n的字符串最后一位是O的个数,D[n][1]代表长度为1的字符串最后一位是非O的个数。

1.由题意我们晓得,D[n][0]最后一位是O,故n-1位长的时候不能选择第n-1为是O的,否则会出现两个O,故只能选最后一位非O的,即

        D[n][0] = D[n-1][1];

2.同上,D[n][1]最后一位非0,故n-1为长的时候可以是非0也可以是0,即有两种办法,且最后一位可以是E或F,要乘以2.即:

        D[n][1] = (D[n-1][0]+D[n-1][1]) * 2;

3.D[1][0] = 1  ,  D[1][1] = 2;

Note:1.n较大时递归很慢,建议用递推。

           2.数据特别大可能会发生溢出,建议用longlong型,(我就Wa了)

附程序:

#include <iostream>
#include <cmath>
using namespace std;

long long D[40][2];//D[n][0]代表最后一位是0的情况,D[n][1]代表最后一位是1的情况。

int main()
{
    int n,i;
    D[1][0] = 1;//即“O”
    D[1][1] = 2;//即“E”,“F”
    for(i=2;i<40;i++)
    {
        D[i][0] = D[i-1][1];
        D[i][1] = 2*(D[i-1][0]+D[i-1][1]);
    }
//    for(i=1;i<40;i++)
//        cout << "D["<< i << "] = " << D[i][0]+D[i][1] << endl;
    while(cin >> n)
    {
        long long x = D[n][0]+D[n][1];
        cout << x << endl;
    }
    return 0;
}

HDU2048:神、上帝 以及 老天爷:

         建议先把列出2,3,4,三种情况自己递推一下,试试行不行,尝试后再看教程。

         我参考大神建议:题目要求的是排错的概率。

首先 要解决的是配对有多少种情况,显然应该是N*(N-1)*(N-2)...1   =     N!。

其次 我们考虑错排的情况,分两种情况考虑。

1.如果前N-1为排错的化,第N位是正确的,我们就要把最后一位和前N-1位中的某一个进行交换 ,这样N位就排错了。

2.如果前N-1为没有排错,加上第N位后与某一个交换导致排错了。那么出现这种情况就是N-1位中有N-2为排错了,有1位正确,则把加进去的第N位与该正确的这位进行交换即可实现排错。

故有递推公式得:F(n) = (n-1) x (   f(n-1) + f(n-2)  ) . 

code:

#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
    int i,n;
    long long d[21][2] = {{0,1},{0,1},{1,2},{2,6}};

    for(i=4;i<=20;i++)
    {
        d[i][0] = (i-1)*(d[i-1][0]+d[i-2][0]);
        d[i][1] = d[i-1][1] * i;
    }
    cin >> n;
    while(n--)
    {
        cin >> i;
        printf("%.2f%%\n",d[i][0]*100.0/d[i][1]);
    }
    return 0;
}

HDU2049:不容易系列之(四)-- 考新郎:

新郎好悲惨,还要经过这么一关,不过要结婚还是最幸福的啦!(本题要点:错排+组合

看了前面的HDU2048,这道题就有思路了。一共有N对夫妻,M对照错了,N-M对配对成功。题目问N对中M对找错的情况,我们1.先找N-M个人,他们是配对成功的,即组合问题,C(N)(N-M)。    2.剩下的M对人表示配错的情况个数,参照HDU2048,我们可以知道F(n) = (n-1) * (F(n-1)+F(n-2) ).

本题Note:1.C(N)(N-M) = C(N)(M) = n! / m! / (n-m)! .         2.数据较大时,建议使用long long 型。

#include <iostream>
using namespace std;
int main()
{
    int c;
    int n,m;
    long long fact[21] = {1,1};
    long long f2[21] = {0,0,1,2};//求M个数排错的数量


    //求 阶乘
    for(int i=2;i<=20;i++)
        fact[i] = i * fact[i-1];
    //求m个数排错可能情况
    for(int i=4;i<=20;i++)
        f2[i] = (i-1)*(f2[i-1]+f2[i-2]);

    cin >> c;
    while(c--)
    {
        cin >> n >> m;
        long long x = fact[n] / fact[m] / fact[n-m] * f2[m];
        cout << x << endl;
    }
    /*test:本函数的目的是检测20以内所有的数的情况,看这些数是否溢出*/
//    for(int i=2;i<=20;i++)
//    {
//        for(int j=1;j<=i;j++)
//        {
//            long long x = fact[i] / fact[j] / fact[i-j] * f2[j];
//            cout << x << " ";
//        }
//        cout << endl;
//    }
}

HDU:2050

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值