思维题——Gym(102302J) Weird Sanchola

题目

Sanchola is getting an array of integers as gift. He’s weird, so he doesn’t like having distinct integers in the same array and he only likes prime numbers. That’s why he believes that he might need to fix the array after receiving it by turning all elements into the same prime number. Sanchola is also very lazy and wants to do that using the minimum number of operations. In one operation Sanchola can either increase or decrease a single element of the array by one. Given the array that he received as a gift, help Sanchola figuring out the minimum number of operations required to fix the array.

Input:The first line contains a single integer N(1<=N<=1e5),including the length of the array. The second line contains N integers a[1],a[2],…,a[n],indicating the elements of the array a.
Output: In a single line output the minimum number of operations to satisfy Sanchola.

Examples
Input
3
2 3 10
Output
8
Input
2
1 1000000000
Output
999999999
Input
4
3 5 7 11
Output
10

题意

给出N个数,每次只能对一个数+1或者-1,求让所有数都变成一个素数要多少步。

解析

错误思路

先排序,然后找距离数组中位数最近的一个素数(先从最中间的两者之间,如果都没有再找整个数组区间,如果还没有再分别在[2,中位数]、[中位数,1e18]中找),最后数组中的每一个数都对它做差求和。前面给的4组样例都会过,但是还会有样例过不了。

错误代码

#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=1e5+5;
#define ll long long
bool is_prime(int u)
{
     
    if(u==0||u==1) return false;
    if(u==2||u==3) return true;
    if(u%2==0) return false;
    else
    {
     
        for(int i=3;i<=sqrt(u);i+=2)
        {
     
            if(u%i==0) return false;
        }
    }
    return true;
}
int n,a[maxn];
int main()
{
     
    int ans1=0,ans2=0,pos1=0,pos2=0,ans=0;
    ll sum=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    int x=n%2+n/2;
    if(is_prime(a[x])==true) for(int i=1;i<=n;i++) sum+=abs(a[i]-a[x]);
    else if(is_prime(a[x+1])==true) for(int i=1;i<=n;i++) sum+=abs(a[i]-a[x+1]);// 但是,其实这样没有考虑到a[x]跟a[x+1]之间可能会有很多个数,只先判断a[x+1]可能会忽略两者之间的更近的点。
    else
    {
     
        for(int i=a[x];i<=1e9;i++)
        {
     
            if(is_prime(i)==true)
            {
     
                ans1=i;
                pos1=i-a[x];
                break;
            }
        }
        for(int i=a[x];i>=2;i--)
        {
     
            if(is_prime(i)==true)
            {
     
                ans2=i;
                pos2=a[x]-i;
                break;
            }
        }
        if(pos1==0) ans=ans2;
        else if(pos2==0) ans=ans1;
        if(pos1<=pos2&&pos1>0) ans=ans1;
        else if(pos1>=pos2&&pos2>0) ans=ans2;
        for(int i=1;i<=n;i++) sum+=abs(a[i]-ans);
    }
    printf("%d\n",sum);
    return 0;
}

参考样例

100
30219 29753 18607 7422 12017 32937 6201 33037 30456 1842
14085 8893 22512 20854 21237 6133 29040 7359 8191 16739
27580 20815 33328 23665 4588 17393 6385 29045 22347 13780
3978 29224 19454 1689 22244 7258 17638 19627 11411 29924
15047 18383 4883 28381 9385 25084 8018 4881 20862 12908
16239 15278 1286 14067 24258 14401 23536 14224 2844 28129
15170 2114 32592 18346 20218 7452 14066 2926 23541 9372
28510 26278 26897 7225 14844 18351 33679 4923 33731 22323
8891 4047 13820 9701 28366 19035 21577 25201 28435 13071
15333 11186 25417 30141 26669 21286 19529 28650 24672 9120
我的答案:791576(错误的ans=18341)
网上的AC代码答案:791570(正确的ans=18353,备用值18341)

100
8828 23377 30948 23463 1498 16640 3772 25259 16229 12246
23068 31279 18483 29342 6251 20617 8592 8327 29425 23922
18848 20274 14490 17594 25414 11018 25846 20794 5445 27092
6277 7177 25765 19334 26162 13299 3673 7517 6685 22822
9246 29482 23965 8495 28838 2797 23686 5925 26358 3748
20391 11300 8461 10341 4247 3069 12742 7339 6834 10796
19967 24302 7518 6923 4347 21622 33683 3397 24581 14704
5274 30604 12630 23618 4628 20111 14905 8988 30527 22310
18541 4047 15733 26832 19147 13795 18933 13408 19752 22243
26854 25331 27517 6396 31129 8485 32838 3015 12303 27269
我的代码(错误)
805773(ans=16633)
正确代码
805759(ans=16633,16649,17597)

正确思路

其他都差不多,主要是找素数的那块有问题。设x=n/2,则n为偶数的时候,数组有两个中位数a[x]、a[x+1];n为奇数的时候,数组只有一个中位数a[x+n%2]。这样来看应该是n为偶数的时候要多一步在a[x]和a[x+1]中找,然后都有共同的步骤——分别在[a[x+n%2],1e18]、[2,a[x+n%2]]中找;这三/二个步骤都要找都要分别计算取最小值,因为不一定是距离中位数最近的素数就是正确值。
–>假设有数组1、2、3、4、5、6、7、8,取4为中位数,2和6相对4的距离都相等。
如果2是要找的数,那么每个元素对2的距离是1、0、1、2、3、4、5、6,总和为22。
如果6是要找的数,那么每个元素对6的距离是5、4、3、2、1、0、1、2,总和为18。
综上,不能根据相对中位数距离的大小来选素数,应该每个区间都找。

正确代码

#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=1e5+5;
#define ll long long
bool is_prime(int u)
{
     
    if(u==0||u==1) return false;
    if(u==2||u==3) return true;
    if(u%2==0) return false;
    for(int i=3;i<=sqrt(u);i+=2)
    {
     
        if(u%i==0) return false;
    }
    return true;
}
int n,a[maxn];
ll cal(int x)
{
     
	ll ans=0;
	for(int i=1;i<=n;i++) ans+=abs(x-a[i]);
	return ans;
}
int main()
{
     
    ll ans=1e18;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    int x=n/2;
    if(n%2==0)
    {
     
        for(int i=a[x];i<=a[x+1];i++)
        {
     
            if(is_prime(i)==true)
            {
     
                ans=min(ans,cal(i));
                break;
            }
        }
    }
    for(int i=a[x+n%2];i<=1e18;i++)//注意不能单纯地用x+1来划分,不然会漏掉区间
    {
     
        if(is_prime(i)==true)
        {
     
            ans=min(ans,cal(i));
            break;
        }
    }
    for(int i=a[x+n%2];i>=2;i--)
    {
     
        if(is_prime(i)==true)
        {
     
            ans=min(ans,cal(i));
            break;
        }
    }
    printf("%lld\n",ans);
    return 0;
}

你可能感兴趣的:(思维题,原创,GYM)