HDU 5798 Stabilization

给定一个正整数序列(序列长度$n \le 10^5$)数字大小 $< 2 ^ {20}$

现选定一个正整数数$x$与原序列中所有的数异或

然后问操作之后的序列相邻两数差的绝对值之和最小是多少

在满足该值最小的前提下 最小的$x$又是多少

---------------------------------------------------------------------------------------

(换句话说就是把$n-1$对数压成$20$对数来算贡献)

$= 2^{20} * 20 * 10 = 2 * 10 ^ 8$ $3s$时限是充足的

 1 #include <cstdio>
2 #include <cstring>
3 #include <cmath>
4 #include <algorithm>
5 using namespace std;
6 const int M = 20, N = 1 << M;
7 long long delta[M][M], ans[N], tans[N];
8 int used[N];
9 int mask[M], nexte[N];
10 int ans1;
11 long long ans2, sum;
12 int t, n, ca;
13 long long dfs(int b, int inv, int x)
14 {
15     if(used[x] == ca)
16         return ans[x] * inv;
17     used[x] = ca;
18     ans[x] = 0;
19     if(!x)
20         return 0;
21     int i = nexte[x];
22         ans[x] = delta[b][i] + dfs(b, 1, x ^ (1 << i));
23     return ans[x] * inv;
24 }
25 int main()
26 {
27     mask[0] = 1;
28     for(int i = 1; i < M; ++i)
29         mask[i] = mask[i - 1] * 2 + 1;
30     for(int i = 2; i < N; ++i)
31         nexte[i] = (i == (i & -i)) ? nexte[i - 1] + 1 : nexte[i - 1];
32     scanf("%d", &t);
33     while(t--)
34     {
35         memset(delta, 0, sizeof delta);
36         sum = 0;
37         int x, y, top, L, R;
38         scanf("%d", &n);
39         scanf("%d", &x);
40         for(int i = 2; i <= n; ++i)
41         {
42             scanf("%d", &y);
43             if(y == x)
44                 continue;
45             top = 19;
46             while((x ^ y ^ (1 << top)) > (x ^ y))
47                 --top;
48             L = min(x, y), R = max(x, y);
49             sum += R - L;
50             delta[top][top] += (L ^ (1 << top)) - (R ^ (1 << top)) - (R - L);
51             for(int j = top - 1; j >= 0; --j)
52                 if((x ^ y) & (1 << j))
53                     delta[top][j] += (R ^ (1 << j)) - (L ^ (1 << j)) - (R - L);
54             x = y;
55         }
56         int M2 = M;
57         while(M2 > 0 && !delta[M2 - 1][M2 - 1])
58             --M2;
59         int N2 = 1 << M2;
60         ans2 = (long long)N2 * n;
61         int inv;
62         for(int i = 0; i < N2; ++i)
63         {
64             inv = i & 1;
65             tans[i] = delta[0][0] * inv;
66         }
67         for(int j = 1; j < M2; ++j)
68         {
69             ++ca;
70             for(int i = 0; i < N2; ++i)
71             {
72                 inv = (i & (1 << j)) != 0;
73                 tans[i] += delta[j][j] * inv + dfs(j, (inv ? -1 : 1), i & mask[j - 1]);
74             }
75         }
76         for(int i = 0; i < N2; ++i)
77             if(tans[i] < ans2)
78             {
79                 ans2 = tans[i];
80                 ans1 = i;
81             }
82         ans2 += sum;
83         printf("%d %lld\n", ans1, ans2);
84     }
85     return 0;
86 }

posted @ 2016-08-05 14:09 sagitta 阅读(...) 评论(...) 编辑 收藏