LightOJ - 1370 Bi-shoe and Phi-shoe 欧拉函数 题解

题目:

Bamboo Pole-vault is a massively popular sport in Xzhiland. And Master Phi-shoe is a very popular coach for his success. He needs some bamboos for his students, so he asked his assistant Bi-Shoe to go to the market and buy them. Plenty of Bamboos of all possible integer lengths (yes!) are available in the market. According to Xzhila tradition,

Score of a bamboo = Φ (bamboo's length)

(Xzhilans are really fond of number theory). For your information, Φ (n) = numbers less than n which are relatively prime (having no common divisor other than 1) to n. So, score of a bamboo of length 9 is 6 as 1, 2, 4, 5, 7, 8 are relatively prime to 9.

The assistant Bi-shoe has to buy one bamboo for each student. As a twist, each pole-vault student of Phi-shoe has a lucky number. Bi-shoe wants to buy bamboos such that each of them gets a bamboo with a score greater than or equal to his/her lucky number. Bi-shoe wants to minimize the total amount of money spent for buying the bamboos. One unit of bamboo costs 1 Xukha. Help him.


Input

Input starts with an integer T (≤ 100), denoting the number of test cases.

Each case starts with a line containing an integer n (1 ≤ n ≤ 10000) denoting the number of students of Phi-shoe. The next line contains n space separated integers denoting the lucky numbers for the students. Each lucky number will lie in the range [1, 106].

Output

For each case, print the case number and the minimum possible money spent for buying the bamboos. See the samples for details.

Sample Input

3

5

1 2 3 4 5

6

10 11 12 13 14 15

2

1 1

Sample Output

Case 1: 22 Xukha

Case 2: 88 Xukha

Case 3: 4 Xukha

题意:

某人为n个人去买竹子,现在我们定义一根竹子的分数为Φ(L),其中L是竹子的长度,Φ(L)是L的欧拉函数值。这n个人分别有各自的幸运数字,某人要买的竹子必须满足一个条件,即:所买竹子的分数要大于等于相应那个人的幸运数字,现在竹子的价格为1长度1Xukha,问:某人为n个人买到满足条件的竹子的最小开销是多少?输出该最小开销。

分析:

本题从题意上来看是欧拉函数的裸题,首先肯定是预处理求出[1,1000000]的欧拉函数值,但是注意到n可以取到10000且幸运数字可以取到1000000,本题的一个难点在于求出欧拉函数值后如何在限定时间内找到满足每一个人条件的最短竹子。如果我们每次都从0到n直接暴力求解每一个人的竹子价格再相加就会面临TLE问题。考虑到这个情况后我使用了二分来枚举符合当前那个人条件的最短竹子,但是还是TLE了,后来我又尝试预处理每一个n的最短竹子后再直接输出答案,很不巧的是还是TLE了(尽管现在还是不明白为什么二分超时了)。

后来参考了一篇题解的思路。【参考链接】https://www.cnblogs.com/sky-stars/p/11221735.html

显然,对任意L>1都有L>Φ(L),我们不妨先对要处理的n个数从小到大排序,在查找这n个数对应的符合条件的Φ(n)时,如果找到了这个数的满足条件的长度j就结束,但是结束的同时j不清零,记下这个j,下一次遍历直接从这个继续遍历,这样一来就可以大幅缩短查找j的时间。

AC code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
set<int> book;
set<int>::iterator it;
map<int,int> L;
bool vis[1000005];
int a[10005];
int tot=0;
int pri[1000005], phi[1000005];
void Get_phi(int N)
{
    phi[1] = 1;
    for(int i=2; i<=N; ++i)
    {
        if(!vis[i])
        {
            pri[++tot] = i;
            phi[i] = i-1;
        }
        for(int j=1,x; j<=tot&&(x=i*pri[j])<=N; ++j)
        {
            vis[x] = true;
            if(i%pri[j] == 0)
            {
                phi[x] = phi[i]*pri[j];
                break;
            }
            else phi[x] = phi[i]*phi[pri[j]];
        }
    }
}
int main()
{
    //freopen("input.txt","r",stdin);
    Get_phi(1000005);
    for(int i=2; i<=1000005; i++)
    {
        if(book.find(phi[i])==book.end())
        {
            book.insert(phi[i]);
            L[phi[i]]=i;
        }
    }
    ll t;
    int k=1;
    scanf("%lld",&t);
    while(t--)
    {
        ll n;
        scanf("%lld",&n);
        ll ans=0;
        for(int i=0; i<n; i++)
            scanf("%d",&a[i]);
        sort(a,a+n);
        int pos=2;
        for(int i=0;i<n;i++)
        {
            for(int j=pos;;j++)
            {
                if(phi[j]>=a[i])
                {
                    pos=j;
                    ans+=j;
                    break;
                }
            }
        }
        printf("Case %d: %lld Xukha\n",k++,ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/cautx/p/11437363.html