您的位置:首页 > 其它

LightOJ 1370 Bi-shoe and Phi-shoe(欧拉函数)

2016-05-27 02:14 489 查看
题目链接:

LightOJ 1370 Bi-shoe and Phi-shoe

题意:

给出n个数,要求对每个数a[i]找一个数x[i]使得小于x[i]且与x[i]互素的数的个数不小于a[i],求出所有x[i]的最小和。

分析:

和最小则每个数对应的x[i]应最小。这道题和欧拉函数定义稍微有点区别,欧拉函数是小于等于a且与a互素的数个数,而这题只能小于。

体现在1上,一般的phi[1] = 1,而这题只能phi[1] = 0.可以先求出欧拉函数,假设phi[i] = j,那么就相当于反过来找

最小的i使得phi[i] >= j。先从小到大遍历一遍欧拉函数对已经求的欧拉函数值反过来赋值,因为是从小到大遍历的,

所以如果已经赋过值了,说明更小的数的欧拉函数就可以得到这个答案,所以可以跳过。那么对于没赋值的数据,说明欧拉函数

的结果没有出现这个数。这时可以从后往前赋值,因为一个数的欧拉函数值能得到更大的结果必然对更小的结果也满足,这就符合了

对每个a[i]找到的x[i]的欧拉函数值不小于a[i],但是有一点需要特别注意!对于一个已经赋过值的数据,是因为有一个数的欧拉函数值正好等于这个数,

但是如果一个更小的数的欧拉函数值大于这个已经赋过值的数据显然也是可以的!

当然看到网上有题解说,对于一个数x要找到一个数t使得t的欧拉函数值大于等于x则t是大于等于x+1的第一个素数,

虽然不是很明白,但是可以AC啊。。。。。。

好像是因为相邻素数之间的合数的欧拉函数值都要小于较小的素数。。。。。。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <climits>
#include <cmath>
#include <ctime>
#include <cassert>
#include <bitset>
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
using namespace std;
typedef long long ll;
const int MAX_N = 3000010;

int T, prime_cnt, n, cases = 0;
int prime[MAX_N / 10], phi[MAX_N], ans[MAX_N];
bitset<MAX_N> bs;

inline void GetPrime() //素数筛
{
bs.set();
prime_cnt = 0;
for(int i = 2; i < MAX_N; i++){
if(bs[i]) { prime[prime_cnt++] = i; }
for(int j = 0; j < prime_cnt && i * prime[j] < MAX_N; j++){
bs[i * prime[j]] = 0;
if(i % prime[j] == 0) break;
}
}
}

inline void GetEuler()
{
GetPrime();
for(int i = 2; i < MAX_N; i++) { phi[i] = i; }  // 1不能带进去!和一般的欧拉函数不一样!
for(int i = 0; i < prime_cnt; i++){
for(int j = prime[i]; j < MAX_N; j += prime[i]){
phi[j] = phi[j] / prime[i] * (prime[i] - 1);
}
}
for(int i = 10; i < 100; i++){
printf("phi[%d] = %d\n", i, phi[i]);
}
}

inline void init()
{
GetEuler();
memset(ans, 0, sizeof(ans));
for(int i = 1; i < MAX_N; i++){
int t = phi[i];
if(t > MAX_N || ans[t]) continue;
ans[t] = i;
}
int pre = INT_MAX;
for(int i = MAX_N  - 10 ; i >= 1; i--){
if(ans[i]) { //已经被赋过值了
pre = min(pre, ans[i]);
ans[i] = min(ans[i], pre); //这里特别注意!不能漏了!
}else { //还没被赋值就从后面的赋值结果中找到最小的
ans[i] = pre;
}
}
}

int main()
{
init();
scanf("%d", &T);
while(T--){
scanf("%d", &n);
ll res = 0;
for(int i = 0; i < n; i++){
int t;
scanf("%d", &t);
res += ans[t];
}
printf("Case %d: %lld Xukha\n", ++cases, res);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  欧拉函数 lightoj