using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public class Program {
public static void Main() {
string line;
while ((line = System.Console.ReadLine ()) != null) { // 注意 while 处理多个 case
int n = int.Parse(line);
line = Console.ReadLine();
string[] t = line.Split(' ');
ulong[] ball = new ulong[t.Length];
for(int i = 0; i < t.Length; i++) ball[i] = ulong.Parse(t[i]);
//排序ball
for(int i = 0; i < ball.Length; i++){
bool swap = false;
for(int j = 0; j < ball.Length - 1 - i; j++){
if(ball[j] > ball[j+1]){
ulong temp = ball[j];
ball[j] = ball[j+1];
ball[j+1] = temp;
swap = true;
}
}
if(!swap) break;
}
//递归遍历所有情况
Console.WriteLine(recursion(0,ball,0,1));
}
}
//递归加球,每次加球只列举从index开始,每种各加1个的情况,不会出现一次递归加了两个一样的球
public static int recursion(int index, ulong[] ball, ulong sum, ulong pro){
int count = 0;
while(index < ball.Length){
sum += ball[index];
pro *= ball[index];
if(sum > pro)
count += 1 + recursion(index + 1, ball, sum, pro);
else if(ball[index] == 1)
count += recursion(index + 1, ball, sum, pro);
else
return count;
ulong temp = ball[index];
sum -= temp;
pro /= temp;
//定位到下一种球的位置
while(++index < ball.Length){
if(ball[index] != temp)
break;
}
}
return count;
}
}
我们不从口袋里拿出球,而是把球一个一个放进口袋,并判断是否是幸运袋子。
为了遍历所有情况而不出现重复,我们举个例子:
对于1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,3,3,3,3,7,7,7
第一个球可以拿
1;2;3;7
第二次拿可以变成
1,1; 1,2; 1,3; 1,7;
2,2; 2,3; 2,7;
3,3; 3,7;
7,7;
我们发现显然第一次拿2的情况下,第二次不可以再拿1,因为2,1和 1,2是一样的
所以我们第i次拿的时候,只需要考虑从i-1次拿的球开始拿
代码思路:
先对ball数组从小到大排序,定义一个递归,它从index处开始拿球,列举第i次可以拿的球的情况,若某种情况下,是幸运袋子,那么count++,调用自身,拿第i+1次;若不满足,有两种情况:1.是在拿第一个球,且第一个球是1,那么我们拿这个球,然后调用自身拿下一个;2.不是第一个球,那么没有再往大的球拿的必要了,因为拿x不是幸运袋子,拿比x大的更不是,直接return count;

京公网安备 11010502036488号