Hdu6092 Rikka with Subset(2017多校第5场) 逆推背包

来源:互联网 发布:算法时代 pdf 编辑:程序博客网 时间:2024/06/05 22:35
/*   1 1 1 3 5   5 1 1 3 1    两个序列的 B序列相同。   那我们可以选择计算  递增的序列(字典序最小)   每次求出一个数的个数 后,删去这个数可以组成的集合 之和对于的个数   那从0~m 扫描, 第一个遇到不是0的就是 单个元素 集合对应和 的个数 */#include<cstdio>#include<cstring>#include<cmath>#include<iostream>#include<vector>#include<algorithm>using namespace std;#define rep(i,a) for(int i=1;i<=int(a);i++)typedef long long ll;const int Size=1e5+5;ll a[Size],c[51][51],dp[Size];int vis[Size];int main(){    int t,n,k;    for(int i=0;i<=50;i++)     for(int j=0;j<=i;j++)     {         if(j==0) c[i][j] =1;         else          {             c[i][j] = c[i-1][j-1];            c[i][j] += c[i-1][j];        }     }    scanf("%d",&t);    while(t--)    {        memset(dp,0,sizeof(dp));dp[0]=1;        int n,m;        scanf("%d%d",&n,&m);        for(int i=0;i<=m;i++) scanf("%lld",&a[i]);        a[0]--;        int ccc=0,ans[60];            for(int i=0;i<=m;i++)         {             if(a[i]>0)              {                  for(int k=0;k<a[i];k++)                  {                     ans[++ccc] =i;                 }                 int tt=a[i];                  for(int j=m;j>=1;j--)                  {                      ll sum=0;                  for(int ii=1;ii<=tt;ii++)                   {                          if(j>=ii*i) sum +=(ll)dp[j-ii*i]*c[tt][ii];                   }                   a[j] -=sum;                   dp[j] +=sum;                }                          }         }         for(int i=1;i<=ccc;i++) printf("%d%c",ans[i],i==ccc?'\n':' ');    }    return 0;}


原创粉丝点击