P3694 邦邦的大合唱站队

原题链接

考察:状压dp

这也能状压?果然是我太弱了.

思路:

        很容易想到压缩相同的数字,采取最暴力的做法就是将m个数字全排列计算代价的最小值.时间复杂度是O(m!)会T爆,所以需要优化.

        假设有队列3个,我们队列顺序为1 2和队列顺序2 1,最后放3.可以发现如果确定了1 2和2 1的最小值后,放3的计算的值是确定的.也就是说,不管前面i个队列怎样排列组合,如果确定了前i个队列的最小值,那么计算i+1的最小值也很容易了.

        因为先放1再放2与先放2再放1效果相同(对3),再结合m只有20可以联想到状压dp.由此就可以想到此题就是哈密顿路径的延伸题.f[i] 假设i为1101,那么代表就是前面放了124队列的最优解.

       一定要预处理i状态下有哪些人,预处理和!!!因为一直T,所以剪了下枝...

 1 #include <iostream>
 2 #include <cstring>
 3 using namespace std;
 4 const int N = 100010,M = 20;
 5 int n,m,sum[M][N],cnt[1<<M];
 6 int f[1<<M];
 7 int main() 
 8 {
 9     scanf("%d%d",&n,&m);
10     for(int i=1;i<=n;i++)
11     {
12         int x; scanf("%d",&x);
13         sum[x-1][i]++;
14         for(int j=0;j<m;j++) sum[j][i]+=sum[j][i-1];
15     }
16     for(int i=1;i<1<<m;i++)
17       for(int j=0;j<m;j++) 
18        if(i>>j&1) cnt[i]+=sum[j][n];
19     memset(f,0x3f,sizeof f);
20     f[0] = 0;
21     for(int i=1;i<1<<m;i++)
22       for(int j=0;j<m;j++)
23         if(i>>j&1)
24         {
25             if(f[i-(1<<j)]>=0x3f3f3f3f) continue;
26             int len = cnt[i-(1<<j)];
27             int now = len+sum[j][n];
28             f[i] = min(f[i-(1<<j)]+now-len-sum[j][now]+sum[j][len],f[i]);
29         }
30     printf("%d\n",f[(1<<m)-1]);
31     return 0;
32 }

 

        

posted @ 2021-04-03 21:01  acmloser  阅读(67)  评论(0编辑  收藏  举报