猴猴吃香蕉 背包DP

猴猴吃香蕉 背包DP

\(D\)次询问,第\(i\)次询问,每次有\(n_i\)个带权香蕉,问有多少方案使香蕉之积为\(k_i\),对结果取模\(1000000007\)

\(n\le 10^3,k\le 10^8,D\le 20\)

背包DP的变种。

\(f[i][j]\)选完第\(i\)个物品时,乘积为\(j\)的方案数。

然后可以发现能组成\(k\)的数一定是\(k\)的约数,所以这个背包的体积就是\(k\)的约数这个集合,这样就可以避免碰\(k\)导致TLE了,这是本题最关键的一点。

实现时可以用map,倒序遍历体积时可用STL的反向迭代器reverse_iterator

#include <cstdio>
#include <map>
#define MOD 1000000007
using namespace std;
inline int read(){
    char ch=getchar();int s=0;
    bool w=0;
    while((ch<'0'||ch>'9')&&(ch!='-')) ch=getchar();
    if(ch=='-'){w=1;ch=getchar();}
    while(ch>='0'&&ch<='9') s=s*10+(ch^'0'),ch=getchar();
    if(w) return -s;
    return s;
}
map<int, int> bag;
map<int, int>::reverse_iterator iter;
int main(){
    int t=read();
    while(t--){
        bag.clear();
        int n=read(),k=read();
        for(int i=1;i*i<=k;++i)
            if(k%i==0) bag[i]=bag[k/i]=0;
        bag[1]=1;
        for(int i=1;i<=n;++i){
            int cur=read();
            if(k%cur!=0) continue;
            for(iter=bag.rbegin();iter!=bag.rend();++iter){
                if(iter->first>=cur&&iter->first%cur==0)
                    iter->second=(iter->second+bag[iter->first/cur])%MOD;
            }
        }
        printf("%d\n", bag[k]);
    }
    return 0;
}

posted @ 2019-11-01 16:42  Santiego  阅读(150)  评论(0编辑  收藏  举报