您的位置:首页 > 编程语言

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

2014-04-12 16:33 309 查看
当然,这也参考了别人的想法,本来是没什么好参考的,编程之美资格门槛题,思路很简单,但是因为以前一看到关于组合算个数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就是为了避免相除又取模,虽然除取模可以用逆元做,但是我脑抽+懒+不懂,所以就用这么土的方式解决了,但是对于我来说解决一个问题不在于方法有多么牛逼,要看对这个问题的解决的效果好坏来评判,最简单+最高效+最适合自己+最简洁+最容易理解的方法我认为才是最好的。好吧,就酱紫啦。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: