[bzoj4971]记忆中的背包

为了使得方案的形式较为单一,不妨强制物品体积为1或$\ge \lceil\frac{w}{2}\rceil$,那么假设最终有$x$个1且$\ge \lceil\frac{w}{2}\rceil$的物品体积依次为$a_{1},a_{2},...,a_{n-x}$,不难发现方案数即为$\sum_{i=1}^{n-x}{x\choose w-a_{i}}$

暴力枚举$x$,并不妨再强制方案数恰为$k$(而不是模$p$意义下),此时即选不超过$n-x$个${x\choose i}$使得其和恰为$k$(其中$i\in [0,\lfloor\frac{w}{2}\rfloor]$,由于$w\ge 50$不妨变为$\in [0,\lfloor\frac{x}{2}\rfloor]$,即问题与$w$无关)

每一次选$i=\max_{0\le j\le 8,{16\choose j}\le k}j$,由于${x\choose 0}=1$,重复此过程最终总可得到$k$,并考虑所有$k\in [0,2\cdot 10^{4}]$后可以发现只需要取$x=13$或$14$即可保证有解

时间复杂度为$o(tn)$,可以通过

(dark_bzoj上该题似乎没有spj)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 15
 4 vector<int>v;
 5 int t,n,m,x,w,C[N][N];
 6 int main(){
 7     for(int i=0;i<N;i++){
 8         C[i][0]=C[i][i]=1;
 9         for(int j=1;j<i;j++)C[i][j]=C[i-1][j-1]+C[i-1][j];
10     }
11     scanf("%d",&t);
12     while (t--){
13         scanf("%d%*d%d",&w,&n);
14         for(int x=13;x<=14;x++){
15             m=n;
16             v.clear();
17             for(int i=0;i<x;i++)v.push_back(1);
18             for(int i=(x>>1);i>=0;i--){
19                 for(int j=0;j<m/C[x][i];j++)v.push_back(w-i);
20                 m%=C[x][i];
21             }
22             if (v.size()<=40){
23                 printf("%d\n",(int)v.size());
24                 for(int i=0;i+1<v.size();i++)printf("%d ",v[i]);
25                 printf("%d\n",v.back());
26                 break;
27             }
28         }
29     }
30     return 0;
31 } 
View Code

 

posted @ 2021-10-01 16:20  PYWBKTDA  阅读(53)  评论(0编辑  收藏  举报