2017 Multi-University Training Contest

来源:互联网 发布:vue.js 2.0 radio 编辑:程序博客网 时间:2024/06/01 07:31

传送门
//这道题比赛的时候没做出来. 太菜了. 只能说思维真的太差了. 这道题真的是思维好题.

//既然组成的和一定处于0-m之间, 那么我们就可以通过遍历组成的m去构成A序列. 对应的A序列增加一个, 则所有相应的这个可以组成的数的单位也要增加一个, 即处理成01背包. 用来限制A的生成. 题目中的最小序列其实感觉不用怎么管, 这样生成的序列一定是符合题目要求的.

AC Code

const int maxn = 1e4+5;int n,m;int a[maxn],b[maxn],c[maxn],dp[maxn];//a存最后的答案. c是中间的辅助记数. dp表示对应此时a序列中的数都构成的方法数.void solve(){    scanf("%d%d",&n,&m);    for(int i=0;i<=m;i++) scanf("%d",&b[i]);    int k = 0; Fill(dp,0); Fill(a,0); Fill(c,0);    dp[0] = 1;   //初始dp[0]=1表示构成0肯定是有一种方案的.    for(int i=1;i<=m;i++){        c[i] = b[i] - dp[i];  //A序列中i的个数        for(int j=1;j<=c[i];j++){            a[k++] = i;  //对A序列赋值            for(int k=m;k>=i;k--){ //处理成01背包                dp[k] += dp[k-i]; //和为k的A子集个数相加去更新B序列            }        }    }    for(int i=0;i<k;i++){        if(i>0) printf(" ");        printf("%d",a[i]);    }    printf("\n");}