# 2172. Maximum AND Sum of Array
###### tags: `Leetcode` `Hard` `Dynamic Programming`
Link: https://leetcode.com/problems/maximum-and-sum-of-array/description/
## 思路
显然是一道要用状态压缩的dp题
一开始的想法是状态压缩nums 但是nums可能比numSlots大一倍 所以压缩numSlots更好
我们用3进制的state表示numSlots 如果第i位是0/1/2 说明第(i+1)个slot有0/1/2个数
于是dp[i][state]表达的是:用完第i个数字、配对了state所表示的slots时,所得的最大价值。所以核心代码大致会是:
```
for (int i=0; i<nums.size(); i++)
for (int nextState=0; nextState<pow(3, numSlots); nextState++)
for (auto pickedSlot: prevState)
dp[i][nextState] = dp[i-1][prevState] + (nums[i] & pickedSlot);
```
对于每一个number 我们遍历所有的nextState(也就是加上这个num之后的state) 然后我们要找到前一个state 然后算出前一个state+把当下number放到某一个slot里面使得state变成nextState所带来的收益
那么怎么找前一个state呢?找出nextState里面所有非空的slot 也就是pickedSlot 给这个slot里面的element数-1 就是前一个state了
### 优化
由于state里面已经涵盖了现在用了几个数字了 所以不需要第一层回圈
**注意: &的优先级比+低 line13一定要给(j+1)&num加括号**
## Code
### 思路一
```java=
class Solution {
public int maximumANDSum(int[] nums, int numSlots) {
int n = nums.length;
int[][] dp = new int[n+1][(int)Math.pow(3, numSlots)];
// Arrays.fill(dp[0], Integer.MIN_VALUE);
// dp[0][0] = 0;
int ans = 0;
for(int i=1; i<=n; i++){
int num = nums[i-1];
for(int state=1; state<Math.pow(3, numSlots); state++){
for(int j=0; j<numSlots; j++){
if(filled(state, j)){
dp[i][state] = Math.max(dp[i][state], dp[i-1][state-(int)(Math.pow(3, j))]+((j+1)&num));
}
}
if(i==n) ans = Math.max(ans, dp[n][state]);
}
}
return ans;
}
private boolean filled(int state, int k){
for(int i=0; i<k; i++){
state/=3;
}
return state%3>=1;
}
}
```
### 优化
```java=
class Solution {
public int maximumANDSum(int[] nums, int numSlots) {
int n = nums.length;
int[][] dp = new int[n+1][(int)Math.pow(3, numSlots)];
int ans = 0;
for(int state=1; state<Math.pow(3, numSlots); state++){
int temp = state;
int count = 0;
while(temp>0){
count += temp%3;
temp/=3;
}
int i = count;
if(i>n) continue;
for(int j=0; j<numSlots; j++){
if(filled(state, j)){
dp[i][state] = Math.max(dp[i][state], dp[i-1][state-(int)(Math.pow(3, j))]+((j+1)&nums[i-1]));
}
}
if(i==n) ans = Math.max(ans, dp[n][state]);
}
return ans;
}
private boolean filled(int state, int k){
for(int i=0; i<k; i++){
state/=3;
}
return state%3>=1;
}
}
```