T1:
数据范围n <= 20,集合问题,dfs视角下考虑优化时间复杂度
发现问题所求为子集和相等方案数,可以采用Meet_in_the_middle
优化,个人观点,采用Meet_in_the_middle优化需要符合问题本身
不具有矢量性(也就是问题本身是不连续的),本题显然符合要求
采用Meet_in_the_middle优化dfs需要考虑的就是Middle处的合
并问题,本题对于每个元素只有选入左集合,不选,选入右集合故
分别赋予权值1,0,-1,最终判断Middle两侧所选集合权值相等的
进行配对即可。注意去重,这里采用bitset记录状态,每次配对Mid
dle两侧时查询与更新状态进行去重
代码如下:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef int I; 4 typedef void V; 5 #define N 20 6 #define len 1 << 10 7 I n,mid,res,m[N]; 8 bitset<len> vis[len]; 9 map< I,bitset<len> > h; 10 V dfs1(I x,I tot,I k) { 11 if (x == mid) return (V) (h[tot][k] = 1); 12 dfs1(x + 1,tot,k); 13 dfs1(x + 1,tot + m[x],k | (1 << x)); 14 dfs1(x + 1,tot - m[x],k | (1 << x)); 15 } 16 V dfs2(I x,I tot,I k) { 17 if (x == n) { if (h.find(tot) != h.end ()) { 18 bitset<len> s(h[tot]); 19 s &= ~vis[k]; vis[k] |= s; res += s.count(); 20 } return; 21 } 22 dfs2(x + 1,tot,k); 23 dfs2(x + 1,tot + m[x],k | (1 << x-mid)); 24 dfs2(x + 1,tot - m[x],k | (1 << x-mid)); 25 } 26 signed main() { 27 scanf ("%d",&n); mid = n >> 1; 28 for (I i(0);i < n; ++ i) scanf ("%d",&m[i]); 29 sort(m,m + n), dfs1(0,0,0), dfs2(mid,0,0); 30 printf ("%d",res - 1); 31 }View Code
T3:
考虑枚举x处理序列,接下来问题为求满足条件的背包负载量最
小值,枚举时间复杂度过不去,显然可以考虑二分答案,也就是说背
包最小负载量关于背包划分数呈单调性,于是二分背包最小负载量进
行判断,剪枝时利用check函数若当前序列无法满足当前最优解则con
tinue,理论上时间复杂度仍然过不去(玄学复杂度事实上能过),考
虑优化枚举,发现随机数据下,最大值只需要二分log次,打乱序列即
可(事实上优化后更慢)
代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define I int 4 #define V void 5 #define B bool 6 const I N = 1e4 + 5; 7 I n,p,k,res(1e8),a[N],b[N],pre[N]; 8 inline B check (I x) { 9 I tot(0); 10 for (I i(1),last(1);i <= n; ++ i) { 11 if (pre[i] - pre[i - 1] > x) return false; 12 if (pre[i] - pre[last - 1] > x) tot ++ ,last = i; 13 } 14 return tot < k; 15 } 16 inline V equin (I l,I r) { 17 while (l < r) { 18 I mid (l + r >> 1); 19 check (mid) ? r = mid : l = mid + 1; 20 } 21 return (V) (res = l); 22 } 23 signed main () { 24 cin >> n >> p >> k; 25 for (I i(1);i <= n; ++ i) cin >> a[i]; 26 for (I i(0);i < p; ++ i) { 27 for (I j(1);j <= n; ++ j) b[j] = (a[j] + i) % p, pre[j] = pre[j - 1] + b[j]; 28 if (check (res)) equin (1,res); 29 } 30 cout << res << endl; 31 }View Code