[bzoj4971]记忆中的背包

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

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

每一次选$i=max_{0le jle 8,{16choose j}le k}j$,由于${xchoose 0}=1$,重复此过程最终总可得到$k$,并考虑所有$kin [0,2cdot 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
",(int)v.size());
24                 for(int i=0;i+1<v.size();i++)printf("%d ",v[i]);
25                 printf("%d
",v.back());
26                 break;
27             }
28         }
29     }
30     return 0;
31 } 
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/15359591.html