Max Score

原题:Max Score

原题大意

给一个数列A,每次从里面取一个数,然后用已经取出的数之和去mod这个数,得到的值加入score里,并且把这个数加入到已经取出的集合里,直到取完所有数,问score最大是多少?

算法分析

本想贪心来写发现完全错了,看了题解才知道用dp,题中给出的n最大为20,所以很容易用位运算进行状态压缩,然后用记忆型dp来写,题解中给出了转移方程:
f(s) = max(f(subset(s,i))) + (∑ e) mod ai;
subset(s,i),指除了ai以外包含s里所有元素的集合
这里的需要枚举i,e属于subset(s,i)。

转移方程详见题解:

https://www.hackerrank.com/contests/rookierank-3/challenges/max-score/editorial

程序代码

#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
int n;
ll a[25];
ll d[1<<21];

ll dp(ll s){
    ll &ans = d[s];
    if(ans != -1) return ans;
    ans = 0;
    if(s == 0) return ans;

    for(int i = 0; i < n; i++){
        ll t, sum;
        if((1<<i)&s){
            t = s ^ (1<<i);//t即为subset(s,i)
            sum = 0;
            for(int j = 0; j < n; j++){
                if((1<<j)&t){
                    sum+=a[n-1-j];
                }
            }
            sum %= a[n-1-i];
            ans = max(dp(t) + sum ,ans);
        }
    }
    return ans;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    mem(d,-1);
    cin >> n;
    for(int i = 0; i < n; i++)
        cin >> a[i];
    ll ans = 0;
    cout << dp((1<<n)-1)<<endl;
    return 0;
}