我有一个像这个[00 01 10 11]
的 S 和一个 E 元素11
。我想找出这个集合的子集数量,其总和大于或等于元素 E 的数字之和。
例如在这种情况下答案是10。 满足约束的10组是:
00 01 10 11 // Sum is 3 which is greater than 2 (sum of digits of E)
00 01 11
00 10 11
01 10 11
00 11
01 11
10 11
11
00 01 10
01 10
上述子集的所有数字之和大于或等于2( E 的数字之和)。
我尝试了以下
public static void main(String[] args) {
Set<String> inputSet = new HashSet<String>();
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
int M = sc.nextInt();// specifies the length of the digts in the set.
for (long i = 0 ; i < N; i++) {
inputSet.add(sc.next());
}
long sum = 0;
String E = sc.next();//
sc.close();
for (String str : E.split("(?!^)")) {
sum = sum + Integer.parseInt(str);
}
List<Set<String>> subSets = new ArrayList<Set<String>>();
for (String addToSets : inputSet) {
List<Set<String>> newSets = new ArrayList<Set<String>>();
for (Set<String> curSet : subSets) {
Set<String> copyPlusNew = new HashSet<String>();
copyPlusNew.addAll(curSet);
copyPlusNew.add(addToSets);
newSets.add(copyPlusNew);
}
Set<String> newValSet = new HashSet<String>();
newValSet.add(addToSets);
newSets.add(newValSet);
subSets.addAll(newSets);
}
long sum1;
long count = 0;
for (Set<String> set : subSets) {
sum1 = 0;
for (String setEntry : set) {
for (String s : setEntry.split("(?!^)")){
sum1 = sum1 + Integer.parseInt(s);
}
}
if (sum == sum1 || sum1 > sum)
count = count+1;
}
System.out.println(count);
}
约束 1 <= N <= 10 ^ 5
1 <= M <= 20
上述方法不适用于10 5 范围的集合的大小。请帮助提供有效的方法。 谢谢!
答案 0 :(得分:2)
解决这个问题的方法就是记住addition is associative
。所以当你添加这些数字并不重要。因此,如果我们将其减少到一个已知问题,那么解决这个问题很容易。
将输入数组转换为sum of digits array
。也就是说,如果您的原始数组是A,那么与结果数组B的关系将是:
B[i] = sum of digits of(A[i]).
说K是sum of digits(E)
然后你的问题就缩小为
Find number of subsets in B whose sum is <= K
这很容易。
编辑:
public static void main(String[] args) {
int[] A ={01,11,111};
int B[] = new int[A.length];
for(int i=0;i<A.length;i++){
B[i]=getDigitSum(A[i]);
}
int E = 11;
int K= getDigitSum(E);
int N =B.length;
Arrays.sort(B);
int DP[][] = new int[B.length][B[B.length-1]+1];
for (int i=0;i<N;i++) {
DP[i][B[i]] = 1;
if (i == 0) continue;
for (int k=0;k<K;k++) {
DP[i][k] += DP[i - 1][k];
}
for (int k=0;k<K;k++) {
if( k + B[i] >= K) break ;
DP[i][k + B[i]] += DP[i - 1][k];
}
}
int sum=0;
for(int i=0;i<K;i++) {
sum = sum +DP[N-1][i];
}
int result = ((int)Math.pow(2,N)) - sum-1;
System.out.println(result);
}
private static int getDigitSum(int num) {
int sum =0;
while(num >0){
sum=sum+ (num%10);
num= num/10;
}
return sum;
}