• 1354 选数字


    1354 选数字

    基准时间限制:1 秒 空间限制:131072 KB
    当给定一个序列a[0],a[1],a[2],...,a[n-1] 和一个整数K时,我们想找出,有多少子序列满足这么一个条件:把当前子序列里面的所有元素乘起来恰好等于K。
    样例解释:

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

    Input
    多组测试数据。在输入文件的第一行有一个整数T(0< T <= 20),表示有T组数据。
    接下来的2*T行,会给出每一组数据
    每一组数据占两行,第一行包含两个整数n, K(1<=n<=1000,2<=K<=100000000)他们的含意已经在上面提到。
    第二行包含a[0],a[1],a[2],...,a[n-1] (1<= a[i]<=K) 以一个空格分开。
    所有输入均为整数。
    Output
    对于每一个数据,将答案对1000000007取余之后输出即可。
    Input示例
    2
    3 3
    1 1 3
    3 6
    2 3 6
    Output示例
    4
    2

    思路:类似于背包的DP,以乘积为状态。先把等选数字里面不是K约数的去掉。然后找出K的约数,进行离散化。然后dp[i][j]表示前i个数字乘积为j的状态。Dp[i+1][j*a[i+1]]]+=dp[i][j].

    Dp[i+1][j]+=dp[i][j];

    dp换成1维的也可以。

     1 #include<stdio.h>
     2 #include<algorithm>
     3 #include<iostream>
     4 #include<string.h>
     5 #include<queue>
     6 #include<stack>
     7 #include<map>
     8 #include<math.h>
     9 #include<set>
    10 using namespace std;
    11 typedef long long LL;
    12 map<LL,LL>my;
    13 set<int>vec;
    14 set<int>::iterator it;
    15 LL ans[1005];
    16 LL mi[100000];
    17 LL dp[100000];
    18 const LL mod = 1e9+7;
    19 int main(void)
    20 {
    21         int T;
    22         scanf("%d",&T);
    23         while(T--)
    24         {
    25                 my.clear();
    26                 int n;
    27                 LL k;
    28                 scanf("%d %lld",&n,&k);
    29                 for(int i = 1; i <= n ; i++)
    30                 {
    31                         scanf("%lld",&ans[i]);
    32                 }
    33                 vec.clear();
    34                 for(int i = 1; i <= sqrt(1.0*n); i++)
    35                 {
    36                         if(k%i == 0)
    37                                 vec.insert(i);
    38                         vec.insert(k/i);
    39                 }
    40                 int ck = 1;
    41                 for(it = vec.begin(); it != vec.end(); it++)
    42                 {
    43                         my[*it] = ck++;
    44                         mi[ck-1] = *it;
    45                 }
    46                 memset(dp,0,sizeof(dp));
    47                 dp[1] = 1;
    48                 for(int i = 1; i <= n; i++)
    49                 {
    50                         if(k%ans[i]==0)
    51                         {
    52                                 for(int j = ck-1; j >= my[ans[i]]; j--)
    53                                 {
    54                                         if(mi[j]%ans[i] == 0)
    55                                         {
    56                                                 dp[j] = dp[my[mi[j]/ans[i]]] + dp[j];
    57                                                 dp[j]%=mod;
    58                                         }
    59                                 }
    60                         }
    61                 }
    62                 printf("%lld
    ",dp[ck-1]);
    63         }
    64         return 0;
    65 }
    油!油!you@
  • 相关阅读:
    bzoj 2816: [ZJOI2012]网络 (LCT 建多棵树)
    bzoj 2157: 旅游 (LCT 边权)
    bzoj 3669: [Noi2014]魔法森林 (LCT)
    bzoj 2049: [Sdoi2008]Cave 洞穴勘测 (LCT)
    bzoj 2002 : [Hnoi2010]Bounce 弹飞绵羊 (LCT)
    bzoj 3282: Tree (Link Cut Tree)
    模拟赛1
    Some tricks
    模拟赛简要题解与心得
    Noip 训练指南
  • 原文地址:https://www.cnblogs.com/zzuli2sjy/p/5869039.html
Copyright © 2020-2023  润新知