编程之美 大神與三位小夥伴

    当然,这也参考了别人的想法,本来是没什么好参考的,编程之美资格门槛题,思路很简单,但是因为以前一看到关于组合算个数or数据过大的题目就望而却步,没想到里面这么简单,看别的思路主要是为了确定这真的很简单,然后提高自己的信心去做罢了=。=

AC代码如下:

#include <iostream>
#include <cstdio>

using namespace std;

int main(){
    long long T,n;
    long long res,mod = (10e8 + 7) * 8;
    scanf("%lld",&T);
    for(long long t = 1;t <= T;t++){
        scanf("%lld",&n);
        res = ((((n  % mod) * (n % mod)) % mod) * ((((n + 1) % mod) * ((n + 1) % mod))) * ((n % mod) * (n % mod) - (3 * n % mod) + 4)) % mod;
        res /= 8;
        printf("Case %lld: %lld\n",t,res);
    }
    return 0;
}
   看这几行代码就知道,简单,主要就只涉及一行公式,还有就是注意变量类型(int太小,long long 合适题目范围),下面说说公式推导:

  题目说送三个人各一个礼物,分别从A_i,B_i,C_i中取,其中A,B,C这三种中又各有N类,每类数目为N+1-i个,限制是不能有两个小伙伴的事一样的而且只限于两个不能一样。其实题目没说清楚,这个题目如果说的很清楚的话人们就会发现其实在A,B,C这三种的每种里的没个都是一个不一样的个体,没有一样的,一样的只有价钱而已,所以,题目说不能有两样一样的只是不能有两一样价钱的,但是他们本身是不一样的东西,虽然可能价钱一样。接下来就是组合了,先进行分类:

    a.先对总体的进行组合,即在没有任何条件的情况下有多少种:

         对于每一个小伙伴,其选择的种类都是:num=1+2+3+...+N=N * (N + 1) / 2

        他们三个小伙伴各有num种,则,三个人组合起来的种类数就是:num^3=num*num*num=[N*(N+1)/2]^3

    b.选出含有两个小伙伴是取同样价值礼物的情况(得注意的是这里不区分是否三个礼物都一样的情况):

        i)先组合两个小伙伴,事先让他们礼物价值一样的合起来,假设所选的伙伴为x和y,则对于价值为i的礼物,x从(N+1-i)挑出一件,有(N+1-i)种选法,同样y也一样,所以,x和y选同样价值i的选法有(N+1-i)^2种,然后对各种价值进行加和,即:1^2 + 2^2 + 3^2 + ... + N^2=N * (N + 1) * (2 * N + 1) / 6------(此为平方和公式);

        ii)由于有三个小伙伴,每两个组合都有上面所说的种类数,而三个小伙伴的组合数有3种(3!/(2! * 1!) = 3)。

       所以,有两个礼物价值相同的情况数为:3 * [N * (N + 1) * (2 * N + 1) / 6]

    c.在b中去除两种价值相同的同时也把三个相同的情况也一并去除了,所以,还得补回三个相同的情况,而三个小伙伴的礼物都相同的情况为:

          1^3+2^3+3^3+...+N^3=[N * (N + 1) / 2]^2--------------(立方和公式)

       因为b中的结果英爱减去c中的结果数(并且是没个小伙伴的组合都得减),所以b和c的组后的结果数为:

         3 * {N * (N + 1) * (2 * N + 1) / 6 - [N * (N + 1) / 2]^2 }

      最后的结果组合数表示为:

        a中组合数 - b和c组合数 = [N*(N+1)/2]^3 - 3 * {N * (N + 1) * (2 * N + 1) / 6 - [N * (N + 1) / 2]^2 }

     上面的公式可以化简,由于过于简单,就不说了,直接给出化简后的公式:

       N^2 * (N+1)^2 * (N^2 - 3 * N + 4) / 8

     代码中之所以给模数在乘以8就是为了避免相除又取模,虽然除取模可以用逆元做,但是我脑抽+懒+不懂,所以就用这么土的方式解决了,但是对于我来说解决一个问题不在于方法有多么牛逼,要看对这个问题的解决的效果好坏来评判,最简单+最高效+最适合自己+最简洁+最容易理解的方法我认为才是最好的。好吧,就酱紫啦。

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值