51nod 1354 选数字【DP】

来源:互联网 发布:上瘾网络剧结局是什么 编辑:程序博客网 时间:2024/06/06 01:09

Description

当给定一个序列a[0],a[1],a[2],…,a[n-1] 和一个整数K时,我们想找出,有多少子序列满足这么一个条件:把当前子序列里面的所有元素乘起来恰好等于K。

对于第一个数据,我们可以选择[3]或者[1(第一个1), 3]或者[1(第二个1), 3]或者[1,1,3]。所以答案是4。

题解

可以发现,m的因数个数很少,所以可以定义f[i][j]表示前i个数,乘起来等于m的第j个因数的方案数。转移的时候可以借助map实现。

代码

#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<map>#define maxn 1006#define maxm 10000006#define maxs 3200#define tt 1000000007using namespace std;inline char nc(){    static char buf[100000],*i=buf,*j=buf;    return i==j&&(j=(i=buf)+fread(buf,1,100000,stdin),i==j)?EOF:*i++;}inline int _read(){    char ch=nc();int sum=0;    while(!(ch>='0'&&ch<='9'))ch=nc();    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();    return sum;}int T,n,m,a[maxn],b[maxn],f[maxn][maxs];map < int,int >p;int main(){    freopen("math.in","r",stdin);    freopen("math.out","w",stdout);    T=_read();    for(int t=1;t<=T;t++){        n=_read();m=_read();p.clear();        for(int i=1;i<=n;i++)a[i]=_read();        int b0=0;        for(int i=2;i<=sqrt(m);i++)if(!(m%i))b[++b0]=i;        for(int i=sqrt(m);i>=1;i--)if(i*i!=m&&!(m%i))b[++b0]=m/i;        for(int i=1;i<=b0;i++)p[b[i]]=i;p[1]=0;b[0]=1;        memset(f,0,sizeof(f));        f[0][0]=1;        for(int i=1;i<=n;i++)         for(int j=0;j<=b0;j++)          if(!(b[j]%a[i])&&p.find(b[j]/a[i])!=p.end())f[i][j]=(f[i-1][j]+f[i-1][p[b[j]/a[i]]])%tt;                                         else f[i][j]=f[i-1][j];        printf("%d\n",f[n][b0]);    }}
原创粉丝点击