ZOJ 3434 Hiiragi's Sticks

Hiiragi's Sticks

Time Limit: 3 Seconds       Memory Limit: 65536 KB

Hiiragi likes collecting sticks. It is said that she has collected m short sticks. One day, she was very excited that she found more sticks from a box under her bed. These new sticks have n different lengths, while for each length, there are infinite sticks of the same length.

Hiiragi then came up with an idea, that concatenates the new sticks in different ways to form long sticks of all possible lengths no longer than L. Let's name the lengths a set S. Her mother told her that "Use each of your m short sticks to measure each of the lengths in S. When you find a short sticks being able to measure a length in integer times, get the times it takes and denote it as t. I will give you one candy if you can find one way that uses the following rules to reduce t to 1."

  1. For a number t, find one of its prime factor p, calculate t1 = t / p.
  2. Use t1 as the new t and go back to the first step until t reaches 1.
Note:  With the same short stick and the same length in  S , two ways are considered to be different iff the reduce processes are not all the same. But it may be counted many times if it's another short stick or the length differs.

So here, you are required to calculate how many candies Hiiragi can get at most.

Input

The first line is T ( ≤ 10), the number of test cases.
Next is T test cases. Each case contains 3 lines. The first line contains three integers n, m, L (n ≤ 20, m ≤ 105L ≤ 106). The second line is n integers indicating the lengths of each kind of sticks found under the bed. The third line is m integers indicating the sticks Hiiragi originally had. All sticks have length no shorter than 1 and no longer than L.

Output

For each case, print one integer, the number of candies Hiiragi can get at most.

Sample Input
1
2 4 12
4 6
1 3 4 3
Sample Output
16
Hint

In the sample, using sticks of length 4 and 6 can make long sticks of S = {4, 6, 8, 10, 12}.
So, with short stick of length 1, Hiiragi can use the following ways
4 -> 2 -> 1
6 -> 3 -> 1
6 -> 2 -> 1
8 -> 4 -> 2 -> 1
10 -> 5 -> 1
10 -> 2 -> 1
12 -> 6 -> 3 -> 1
12 -> 6 -> 2 -> 1
12 -> 4 -> 2 -> 1
to get 9 candies. Also, with short sticks of length 3, 4 and 3 she can get 2, 3 and 2 candies each. So all she can get is 9 + 2 + 3 + 2 = 16 candies.


题意:一个小朋友,已经有了m根木棍,有一天他在床底下突然又发现了n种木棍,注意是种,每种无限多个,发现的n种木棍可以随意拼凑成任意长度,范围在 1 到 L之间,得到一个集合S。然后用以前有的m根木棍去S中测量拼凑的长木棍,用于测量的木棍必须是S中木棍的因子,即 t=Si / Mi  t 要为整数。得到t之后,小朋友的妈妈说,如果小朋友能每次把t除以t的质因数,让t变成 1,那么就能得到一个糖,问最多可以得到几个糖,也就最多多少种测量方法。

#include <iostream>
#include <stdio.h>
#include <string>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
const int MM=1000009;
typedef long long ll;

using namespace std;
bool dp1[MM];//只用 0 1所以用bool,节省内存,int会爆。
ll dp2[MM];
vector<int>p[MM];

int main()
{
    int T;
    int n,m,L;
    int a;

    for(int i=2;i<MM;i++)
    if(p[i].empty())
    {
        for(int j=i;j<MM;j+=i)
        p[j].push_back(i);//记下每个数的质因数
    }

    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&L);
        memset(dp1,0,sizeof dp1);
        memset(dp2,0,sizeof dp2);

        dp1[0]=1;//相减后为0,表示存在这个数,所以标记为1
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a);
            for(int j=a;j<=L;j++)
            dp1[j]|=dp1[j-a];//求出S集合中元素,标记为1
        }

        for(int i=0;i<m;i++)
        {
            scanf("%d",&a);//dp2[x]表示,凑成x长度的木棍的方法数
            dp2[a]++;//当前存在这个长度,那么t=(x/x)=1,可以获得一个糖
        }

        for(int i=2;i<=L;i++)
        {
            for(int j=0;j<p[i].size();j++)
            dp2[i]+=dp2[i/p[i][j]];
            //递推过程,每次都枚举质数被
            //12-(/2)->6-(/3)->2-(/2)->1,dp[12]+=dp[12/2];dp[6]已经在之前求出
            //12-(/3)->4-(/2)->2-(/2)->1,dp[12]+=dp[12/3];dp[4]已经在之前求出
        }

        ll ans=0;
        for(int i=1;i<=L;i++)
        {
            if(dp1[i])
            ans+=dp2[i];
        }

        printf("%lld\n",ans);
    }

    return 0;
}








  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值