CF327E Axis Walking 解题报告
题意
给出一堆数,让你对其进行排序,求有多少种方案满足任意前缀和不会出现给定的数字。
数据范围:\(1\le n\le 24\),\(0\le m\le 2\)
思路
首先考虑使用dp。
因为没有给出 \(a_i\) 的具体范围,所以不把距离设计进状态。
又发现每个数字只能用一次并且没有顺序限制,观察到 \(n\) 的范围也很小,我们可以考虑状压dp。
定义 \(dp[i]\) 表示使用了集合 \(i\) 内的卡片有多少种赢的方案。转移时,我们记 \(dis[i]\) 表示使用了集合 \(i\) 内的卡片到达的位置,显然当 \(dis[i]\) 为给定数字时不能转移。否则我们枚举这次使用的卡片 \(j\),那么有转移方程:\(dp[i]=\sum_{j=1}^ndp[i | j]\)
其中 \(i | j\) 是从集合 \(i\) 中删去元素 \(j\)。
时间复杂度 \(O(2^n\log n)\)
代码
#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
const int QWQ = (1 << 24);
int n, m, b[3], a[25], dp[QWQ], f[QWQ];
int lowbit(int x)
{
return x & -x;
}
bool check(int x)
{
for(int i = 1; i <= m; i ++)
{
if(x == b[i]) return 0;
}
return 1;
}
signed main()
{
cin >> n;
for(int i = 1; i <= n; i ++)
{
cin >> a[i];
f[1 << (i - 1)] = a[i];
}
cin >> m;
for(int i = 1; i <= m; i ++)
{
cin >> b[i];
}
dp[0] = 1;
for(int i = 1; i <= (1 << n) - 1; i ++)
{
int qwq = i & -i;
f[i] = f[i ^ qwq] + f[qwq];
if(f[i] == b[1] || f[i] == b[2])
{
continue;
}
for(int j = i, k; j > 0; j ^= k)
{
k = j & -j;
dp[i] += dp[i ^ k];
dp[i] %= mod;
}
}
cout << dp[(1 << n) - 1] % mod << endl;
}

浙公网安备 33010602011771号