[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
标签:lceil,背包,frac,bzoj4971,int,ge,le,记忆,choose 来源: https://www.cnblogs.com/PYWBKTDA/p/15359591.html