猴猴吃香蕉 背包DP

猴猴吃香蕉 背包DP

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

(nle 10^3,kle 10^8,Dle 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
", bag[k]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/santiego/p/11777935.html