Problem: A (Digital DP & shaped pressure)

topic

Thinking

Immortal digital DP title

Initially thought is ternary-like pressure

Each bit represents the number of the same, increase or decrease

\ (dp_ {k, s, i, 0/1} \) represents the k-th bit into consideration, state s, is considering the i-th, k-th and the exclusive OR is 0/1

Thus,

The time complexity is to \ (O (32 * n * 3 ^ n) \)

Obviously instantaneous explosion

But we think carefully about increases and decreases

If this is higher than the median number of his overall value has been assigned back

If the increase is

Then the price is \ (2 ^ i \)

If you reduce it?

The price is \ (2_i \)

That our state can be converted into a binary

But we need more than the increase a bit to represent whether it is higher than his overall assignment of bits

I called constraint

\ (dp_ {k, s, i, 0 / 1,0 / 1} \) represents consideration of the k-th bit, the status bits s, the i-th first bit s and the exclusive OR is 0/1, the i whether the number of k bits is restricted

First, we consider the transfer of DP can be found, the current state of the k-bit only state with the first k + 1 bits about

That is, we can roll k

I-number is completely unnecessary

Modified directly on the line

I too dishes directly attached to the STD code

Code

#include <cstdio>
#include <cstring>
#include <algorithm>

#define rep(i, x, y) for (int i = (x), _ = (y); i <= _; ++i)
#define down(i, x, y) for (int i = (x), _ = (y); i >= _; --i)
#define x first
#define y second
#define mp make_pair
#define pb push_back
#define bin(x) (1<<(x))
//#define LX_JUDGE

using namespace std;
typedef long long LL;
typedef pair<int, int> pii;

template<typename T> inline void upmax(T &x, T y) { x < y ? x = y : 0; }
template<typename T> inline void upmin(T &x, T y) { x > y ? x = y : 0; }

template<typename T>
inline void read(T &x) {
    char c;
    while ((c = getchar()) < '0' || c > '9');
    for (x = c - '0'; (c = getchar()) >= '0' && c <= '9'; x = x * 10 + c - '0');
}

const int inf = 0x3f3f3f3f;
const int maxn = 15;

int dp[2][bin(maxn) + 1][2][2];
int a[maxn], n;

void Solve() {
    read(n);
    rep (i, 0, n - 1) {
        read(a[i]);
    }
    memset(dp[0], 0x3f, sizeof(dp[0]));
    dp[0][0][0][0] = 0;
    /*
    原状态为dp[s][i][0/1][0/1]表示考虑到第s高位,每一个数是否能增减的状态为i,第k位的异或位0/1 第k位是否被高位所束缚 
    但是我们考虑到因为我们是从高到低枚举,
    所以s这一位可以滚动
    */
    int fr = 0, to = 1;
    down (s, 30, 0) //每一位
    {
        rep (i, 0, n - 1) //枚举每一个数
        {
            int v = (a[i] >> s) & 1;//第a[i]个数的s为是否为1
            int cost = a[i] & (bin(s) - 1);//除去最高位到第s位之后的a[i]
            cost = !v ? bin(s) - cost : cost + 1;//如果当前的位置是0,把他变为全0,否则就变为全1,所造成的花费,并且是第一次改的
            memset(dp[to], 0x3f, sizeof(dp[to]));
            rep (j, 0, bin(n) - 1) //枚举每一个数能否增减
            {
                rep (l, 0, 1) //枚举第s位的异或值
                    rep (o, 0, 1) //枚举当前这一位是否被约束
                    {
                        int x = dp[fr][j][l][o];
                        if (j & bin(i)) //已经被修改过
                        {
                            upmin(dp[to][j][l][o], x);//从上一个数字原地转移
                            upmin(dp[to][j][l ^ 1][o], x + bin(s));//l^1表示异或变化,所导致的费用增加,因为不是第一次改,第s位的增减的费用变化是2^s,
                        } 
                        else //没有被修改过
                        {
                            upmin(dp[to][j][l ^ v][o], x);//一样的原地转移
                            upmin(dp[to][j | bin(i)][l ^ v ^ 1][o ^ v], x + cost);
                            //j|bin(i)表示第i个数发生了变化,l^v^1表示当前的异或变化,o^v表示当前第i位强行打破了约束,或者成为了约束
                        }
                }
            }
            swap(fr, to);//滚动
        }
        rep (j, 0, bin(n) - 1) //初始化
        {
            dp[fr][j][1][0] = inf;
            dp[fr][j][1][1] = dp[fr][j][0][1];
            dp[fr][j][0][1] = inf;
        }
    }
    int ans = inf;
    rep (i, 0, bin(n) - 1) {
        upmin(ans, min(dp[fr][i][0][0], dp[fr][i][1][1]));
    }
    printf("%d\n", ans);
}

int main() {
#ifdef LX_JUDGE
    freopen("in.txt", "r", stdin);
#endif
    freopen("a.in", "r", stdin);
    freopen("a.out", "w", stdout);
    int kase;
    read(kase);
    while (kase--) {
        Solve();
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}

Guess you like

Origin www.cnblogs.com/loney-s/p/12034668.html