编程之美资格赛 大神与三位小伙伴

题目2 : 大神与三位小伙伴

时间限制:2000ms

单点时限:1000ms

内存限制:256MB

描述

L国是一个有着优美景色且物产丰富的国家,很多人都喜欢来这里旅游并且喜欢带走一些纪念品,大神同学也不例外。距离开L国的时间越来越近了,大神同学正在烦恼给她可爱的小伙伴们带什么纪念品好,现在摆在大神同学面前的有三类纪念品A, B, C可以选择,每类纪念品各有N种。其中种类为A_i, B_i, C_i的纪念品价值均为i, 且分别有N+1-i个剩余。现在大神同学希望在三类纪念品中各挑选一件然后赠送给她的三名可爱的小伙伴,但是她又不希望恰好挑出来两件价值相同的纪念品,因为这样拿到相同价值纪念品的两位小伙伴就会认为大神同学偏袒另一位小伙伴而不理睬她超过一星期。现在,大神同学希望你买到的三件纪念品能让三位小伙伴都开心并且不和她闹别扭,她想知道一共有多少种不同挑选的方法?

因为方案数可能非常大,大神同学希望知道挑选纪念品的方案数模10^9+7之后的答案。

输入

第一行包括一个数T,表示数据的组数。

接下来包含T组数据,每组数据一行,包括一个整数N。

输出

对于每组数据,输出一行“Case x: ”,其中x表示每组数据的编号(从1开始),后接一个数,表示模10^9+7后的选择纪念品的方案数。

数据范围

小数据:

1<=T<=10

1<=N<=100

大数据:

1<=T<=1000

1<=N<=10^18

样例解释

对于第二组数据,合法的方案有以下几种,(X,Y,Z)表示选择了A类纪念品中价值为X的,B类纪念品中价值为Y的,C类纪念品中价值为Z的。

(1,1,1): 3*3*3=27种

(1,2,3): 3*2*1=6种

(1,3,2): 3*1*2=6种

(2,1,3): 2*3*1=6种

(2,2,2): 2*2*2=8种

(2,3,1): 2*1*3=6种

(3,1,2): 1*3*2=6种

(3,2,1): 1*2*3=6种

(3,3,3): 1*1*1=1种

一共27+6+6+6+8+6+6+6+1=72种选择纪念品的方案

注意,如(1,1,2), (2,3,3), (3,1,3)都因为恰好选择了两件价值相同的纪念品,所以并不是一种符合要求的纪念品选择方法。

样例输入
2
1
3
样例输出
Case 1: 1
Case 2: 72

解法一:

由于(1,2,3)、(1,3,2)、(2,1,3)、(2,3,1)、(3,2,1)、(3,1,2)的种数都是都是一样的,可递推出N时存在只需计算其中一种组合,再x6即可算出所有排列后的种数和。代码很简单,小数据都可以轻松过,但大数据就不行了。。。

#include <stdio.h>
#define llong unsigned long long
#define MOD 1000000007

llong muti_mod(llong a,llong b)//(a*b)mod MOD
{
     a%=MOD;
     b%=MOD;

     llong ret=0;
     while (b)//fast mul
     {
          if (b&1)//a*b=a+a(b-1)
          {
               ret+=a;//ret = (ret + a)%c
               if (ret>=MOD)
                    ret-=MOD;
          }
          //a*b=a*2 *b/2
          b>>=1;
          a<<=1;
          if (a>=MOD)
               a-=MOD;
     }
     return ret;
}

int main(void)
{
     unsigned int T=0,num=0,i=0,j=0,k=0;
     llong N=0,sum=0;

     scanf("%d",&T);

     while(num<T)
     {
          scanf("%lld",&N);
          sum=0;

          for (i=1;i<=N;i++)
          {
               for (j=i+1;j<=N;j++)
               {
                    #pragma omp parallel for reduction(+: sum)
                    for (k=j+1;k<=N;k++)
                    {
                         if (i!=j&&j!=k&&i!=k)//123 124 234 134
                         {
                              sum+=6*muti_mod(muti_mod(N+1-i,N+1-j),(N+1-k));
                              sum=sum%MOD;
                         }
                    }
               }
               //111 222 333
               sum+=muti_mod(muti_mod(N+1-i,N+1-i),(N+1-i));
               sum=sum%MOD;
          }
          printf("Case %d: %lld\n",++num,sum);
     }
     return 0;
}

结果如图

解法二:

考虑动态规划,算出f(n)与f(n-1)的关系,在利用数学归纳法算出f(n)的表达式:f(n) = n^2 * (n+1)^2 * (n^2-3n+4)/8。这样下来大数据也是毫秒过~~

#include <stdio.h>
#define llong unsigned long long
#define MOD 1000000007

llong muti_mod(llong a,llong b)//(a*b)mod MOD
{
     a%=MOD;
     b%=MOD;

     llong ret=0;
     while (b)//fast mul
     {
          if (b&1)//a*b=a+a(b-1)
          {
               ret+=a;//ret = (ret + a)%c
               if (ret>=MOD)
                    ret-=MOD;
          }
          //a*b=a*2 *b/2
          b>>=1;
          a<<=1;
          if (a>=MOD)
               a-=MOD;
     }
     return ret;
}

int main(void)
{
     unsigned int T=0,num=0;
     llong N=0,sum,tmp2,tmp3,tmp4,tmp5;

     scanf("%d",&T);

     while(num<T)
     {
          sum=0;
          tmp2=0;
          tmp3=0;
          tmp4=0;
          tmp5=0;

          scanf("%lld",&N);

          #pragma omp parallel sections
          {
               #pragma omp section
               {
                    if(N&1)//
                    {
                         tmp2=muti_mod(N,N);//n^2
                         tmp3=muti_mod((N+1)>>1,(N+1)>>1);//n^3 /4
                    }
                    else
                    {
                         tmp2=muti_mod(N>>1,N>>1);//n^2 /4
                         tmp3=muti_mod(N+1,N+1);//n^3
                    }
                    tmp4=muti_mod(tmp3,tmp2);//n^3 * n^2 /4
               }

               #pragma omp section
               {
                    if(N<3)
                         tmp5=(4+N*N-3*N)/2;//(n^2-3N+4)/2
                    else
                    {
                         if(N&1)//
                              tmp5=muti_mod(N,(N-3)>>1)+2;//n*(n-3)/2+2
                         else
                              tmp5=muti_mod(N>>1,N-3)+2;//n/2*(n-3)+2
                    }
               }
          }
          sum=muti_mod(tmp5,tmp4);//f(n) = n^2*(n+1)^2*(n^2-3n+4)/8

          printf("Case %d: %lld\n",++num,sum);
     }
     return 0;
}

运行结果

部分计算过程如下,我的成果啊~~

编程之美资格赛 大神与三位小伙伴

时间: 2024-10-07 22:40:36

编程之美资格赛 大神与三位小伙伴的相关文章

2014编程之美-资格赛-大神与三位小伙伴

题目2 : 大神与三位小伙伴 时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 L国是一个有着优美景色且物产丰富的国家,很多人都喜欢来这里旅游并且喜欢带走一些纪念品,大神同学也不例外.距离开L国的时间越来越近了,大神同学正在烦恼给她可爱的小伙伴们带什么纪念品好,现在摆在大神同学面前的有三类纪念品A, B, C可以选择,每类纪念品各有N种.其中种类为A_i, B_i, C_i的纪念品价值均为i, 且分别有N+1-i个剩余.现在大神同学希望在三类纪念品中各挑选一件然后赠送给

编程之美 大神与三个小伙伴

#include <iostream> #include <cmath> using namespace std; const long long great = 1000000007; bool isSame(long long a, long long b, long long c) { if (a == b && b == c) return true; if (a == b) return false; if (b == c) return false; i

[2015编程之美] 资格赛C

#1150 : 基站选址 时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 需要在一个N × M的网格中建立一个通讯基站,通讯基站仅必须建立在格点上. 网格中有A个用户,每个用户的通讯代价是用户到基站欧几里得距离的平方. 网格中还有B个通讯公司,维护基站的代价是基站到最近的一个通讯公司的路程(路程定义为曼哈顿距离). 在网格中建立基站的总代价是用户通讯代价的总和加上维护基站的代价,最小总代价. 输入 第一行为一个整数T,表示数据组数. 每组数据第一行为四个整数:N, M

MySQL---数据库从入门走上大神系列(三)-修改数据库编码/DOS窗口编码

如何查看与修改数据库的编码,如何修改dos窗口的显示编码,都在本篇详细讲解. 查看当前数据库的编码: show variables where variable_name like 'character%'; 如果出现了中文乱码,我们只要看: character_set_client -客户端的编码 character_set_connection -连接的编码(传输时的编码) character_set_results - 最后的输出编码 只要保证这三个编码是相同的,且编码集有中文,中文就不会

2014微软编程之美初赛第一场第三题 活动中心

活动中心 时间限制:12000ms 单点时限:6000ms 内存限制:256MB 描写叙述 A市是一个高度规划的城市,可是科技高端发达的地方,居民们也不能忘记运动和锻炼,因此城市规划局在设计A市的时候也要考虑为居民们建造一个活动中心,方便居住在A市的居民们能随时开展运动,锻炼强健的身心. 城市规划局希望活动中心的位置满足下面条件: 1. 到全部居住地的总距离最小. 2. 为了方便活动中心的资源补给和其它器材的维护,活动中心必须建设在A市的主干道上. 为了简化问题.我们将A市摆在二维平面上,城市的

[编程之美]资格赛 B Palindrome

既然这个是资格赛,  时间也比较充裕, 我就讲解一下我做题的过程 Time Limit:2000ms Case Time Limit:1000ms Memory Limit:256MB Description Given a string, calculate the number of subsequences that are palindrome. A palindrome is a sequence of characters that reads the same backward o

编程之美资格赛 第二题 回文字符序列 dp

这是一道dp题,设置dp[i][j]代表的是从i到j之间的有多少个回文子串,dp[i][j] = dp[i][num[1]] +1+ dp[num[1]+1][j - 1]+1......+dp[num[j]][j-1] + 1 ,num[i] 代表的是与i字符相同的上一个字符的位置! 时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 给定字符串,求它的回文子序列个数.回文子序列反转字符顺序后仍然与原序列相同.例如字符串aba中,回文子序列为"a", &quo

2015编程之美资格赛 回文子序列个数

时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 给定字符串,求它的回文子序列个数.回文子序列反转字符顺序后仍然与原序列相同.例如字符串aba中,回文子序列为”a”, “a”, “aa”, “b”, “aba”,共5个.内容相同位置不同的子序列算不同的子序列. 输入 第一行一个整数T,表示数据组数.之后是T组数据,每组数据为一行字符串. 输出 对于每组数据输出一行,格式为”Case #X: Y”,X代表数据编号(从1开始),Y为答案.答案对100007取模. 数据范围 

2015编程之美资格赛 A 2月29日

 时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 给定两个日期,计算这两个日期之间有多少个2月29日(包括起始日期). 只有闰年有2月29日,满足以下一个条件的年份为闰年: 1. 年份能被4整除但不能被100整除 2. 年份能被400整除 输入 第一行为一个整数T,表示数据组数. 之后每组数据包含两行.每一行格式为"month day, year",表示一个日期.month为{"January", "February&quo