牛客
解题思路:
每次从全集中选择若干元素(小球)组成子集(袋子)。 对于任意两个正整数a,b如果满足 a+b>ab,则必有 一个数为1.可用数论证明:设a=1+x,b=1+y,则1+x+1+y>(1+x)(1+y),---> 1>xy,则x,y必有一个为0,即a,b 有一个为1. 推广到任意k个正整数,假设a1,a2,...ak,如果不满足给定条件,即和sum小于等于积pi。如果此时再选择一个数b,能使其满足sum+b > pib,则,b必然为1,且为必要非充分条件。反之,如果选择的b>1,则 sum+b <= pi*b,即a1,a2,...,ak,b不满足给定条件。
因此,将球按标号升序排序。每次从小到大选择,当选择到a1,a2,...,ak-1时满足给定条件,而再增加选择ak 时不满足条件(ak必然大于等于max(a1,a2,...,ak-1)),继续向后选择更大的数,必然无法满足!此时不必再继续向后搜索。 如果有多个1,即当k=1时,sum(1)>pi(1)不满足,但下一个元素仍为1,则可以满足 1+1>1*1, 所以要判断当前ak是否等于1,如果等于1,虽然不能满足,组合的个数不能增加,但是继续向后 搜索 , 仍然有满足条件的可能 .对于重复数字,组合只能算一个,要去重.
代码:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int Solution(vector<int>& ans , int n , int pos , int sum ,int mul)
{
int count = 0 ;
for(int i = pos;i < n ;++i)
{
sum += ans[i];
mul *= ans[i];
if(sum > mul)
{
count += 1 + Solution(ans,n,i+1,sum,mul);
}
else if(ans[i] == 1) //连续的1
{
count += Solution(ans , n ,i+1 , sum , mul);
}
else //因为是有序的,只要后面一个不成立,后面的都不成立
{
break;
}
//回溯
sum -= ans[i];
mul /= ans[i];
//对于重复数字,组合只能算一个,要去重
while(i < n-1 && ans[i] == ans[i+1])
{
i++;
}
}
return count;
}
int main()
{
int n;
cin>>n;
vector<int> ans(n);
for(int i = 0 ; i < n ; i++)
{
cin>>ans[i];
}
sort(ans.begin() , ans.end()); //使序列升序
cout << Solution(ans, n, 0 , 0 , 1)<<endl;
return 0;
}