NowCoder110E Pocky游戏 状压DP

传送门

题意:给出$N$个数和一个长为$M$、所有数在$[1,N]$范围之内的正整数序列$a_i$,求出这$N$个数的一种排列$p_1...p_N$使得$\sum\limits_{i=2}^M |p_{a_i}-p_{a_{i-1}}|$最小。$N \leq 20,M \leq 1000$


 $N \leq 20$给了我们很明显的状压DP的信息,但是DP方程的思维难度还是有点大。

我们考虑按照数字从小到大地指定它在$p_i$中的位置。这样我们可以通过预处理某一个位置在$a_i$中相邻位置的数字的情况得到这一个数的贡献(也就是可以直接把绝对值符号拆开来计算它的贡献),这样子转移就会方便很多了。

设$f_i$表示已经指定了数字的序列$p$中的元素集合为$i$(eg.$i=10101$就表示指定了$p_1,p_3,p_5$,而$i=01011$表示指定了$p_1,p_2,p_4$),且对应的数为$N$个数中最小的若干个时,最小的难度值为多少。我们可以预处理$g_{i,j}$表示在序列$a$中与$i$相邻的且在集合$j$中的数的出现次数的总和(eg.如果有某一对相邻的数对为$2,3$,那么$g_{2,2^3}++,g_{3,2^2}++$),这样我们转移的时候只需要取$g_{k,i}-g_{k,2^N - 1 \, xor \, i}$就可以得到这一个数的贡献(也就是拆了绝对值之后的系数)。然后枚举转移点转移即可。

看到绝对值就要考虑一下从小到大然后拆掉绝对值符号算贡献呢qwq

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3  
 4 int now[21] , dp[1 << 21] , cnt[21][1 << 21] , cnt1[1 << 21] , N , M;
 5  
 6 inline int lowbit(int x){
 7     return x & -x;
 8 }
 9  
10 int main(){
11     cin >> N >> M;
12     for(int i = 0 ; i < N ; i++)
13         cin >> now[i];
14     int last = -1;
15     while(M--){
16         int x;
17         cin >> x;
18         x--;
19         if(last != -1){
20             cnt[last][1 << x]++;
21             cnt[x][1 << last]++;
22         }
23         last = x;
24     }
25     memset(dp , 0x3f , sizeof(dp));
26     dp[0] = 0;
27     sort(now , now + N);
28     for(int i = 1 ; i < 1 << N ; i++)
29         for(int j = 0 ; j < N ; j++)
30             cnt[j][i] = cnt[j][i - lowbit(i)] + cnt[j][lowbit(i)];
31     for(int i = 1 ; i < 1 << N ; i++){
32         cnt1[i] = cnt1[i - lowbit(i)] + 1;
33         for(int j = 0 ; j < N ; j++)
34             if(i & (1 << j))
35                 dp[i] = min(dp[i] , dp[i ^ (1 << j)] + (cnt[j][i] - cnt[j][(1 << N) - 1 - i]) * now[cnt1[i] - 1]);
36     }
37     cout << dp[(1 << N) - 1];
38     return 0;
39 }

转载于:https://www.cnblogs.com/Itst/p/9833372.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值