原题链接
一、题目描述
小蓝有 k 种卡片, 一个班有 n 位同学, 小蓝给每位同学发了两张卡片, 一 位同学的两张卡片可能是同一种, 也可能是不同种, 两张卡片没有顺序。没有 两位同学的卡片都是一样的。
给定 n, 请问小蓝的卡片至少有多少种?
如果有3种卡片
小朋友们手中的卡片可能是: (1,1),(1,2),(1,3),(2,2),(2,3),(3,3),至多6人可用。
如果有2中卡片
则是:(1,1),(2,2),(1,2),至多3人可用。
所以n(人数)为4,5,6时,答案就是3
二、思路
很明显,至多可用人数(n) = C k 2 + k C_k^2+k Ck2+k,1<=n<= 1 0 9 10^9 109。
k ! 2 ! ( k − 2 ) ! + k > = 1 0 9 \frac{k!}{2!(k-2)!}+k>=10^9 2!(k−2)!k!+k>=109,计算得出k = 44722种卡牌。
当然,设置好枚举条件不计算k的最大值也可以
使用[2,3,5,7]四个数生成数字,将生成的数字按其位数分成不同阶段,个位数是一个阶段,十位数是一个阶段,每个阶段符合超级质数要求的数字都放入prime数组中,prime[i][j]表示 i 阶段产生的集合中的第 j 个元素。
当前阶段用于判断的数字从上一个阶段的集合中与[2,3,5,7]组合生成,如此便保证了当前阶段数字的前n-1位是超级质数,再判断后n-1位数是否在上一个阶段的集合中,如果是,即可确定其是当前阶段的超级质数。
三、代码
代码如下(示例):
#include <iostream>
using namespace std;
// C(k,2)+k ,返回k种卡牌时,最多n人可用
long long C(int n){
if(n<2)
return 1LL;
int i,j;
long long sum = 1;
for(j=1,i=n;j<=2;j++)
sum = sum*(i-j+1)/j;
return sum+n*1LL;
}
int main()
{
int n;
cin >> n;
int i;
int k=0;
for(i=1;i<=44722&&k<n;i++){
k = C(i);
if(k>=n)
cout << i;
}
return 0;
}
总结
高中知识与编程的有机结合。