NOIP 模拟30

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两侧时查询与更新状态进行去重

代码如下:

NOIP 模拟30
 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次,打乱序列即

可(事实上优化后更慢)

代码如下:

NOIP 模拟30
 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

 

上一篇:[hdu7020]Array


下一篇:「CF612D」题解