Kuroni and the Punishment CodeForces - 1305F 随机函数mt19937 + 质因子分解

题意:

给你n个数,你每次操作可以对一个数加1或者减1,让你求你最少需要操作多少次可以使这n个数的公因子大于1

 

 

题解:

正常方法就是枚举质因子(假设质因子为x),然后对于这个数组中的数a[i],让a[i]变成x的倍数的最小操作数为:

1、如果a[i]不为0

答案为:min(a[i]%x,x-a[i]%x)

2、a[i]为0

答案为:x

 

后面的思路参考博客:https://blog.csdn.net/qq_41818939/article/details/104658566

 

假设最大公约数为2时,每个数最多只需要操作一次就可以了,所以操作次数最多为n。所以需要操作次数≤1的数的数量≥n/2。
一个数x操作次数≤1时候会变成x,x+1,x-1三种情况,所以我们可以随机一下需要操作次数≤1的数,这时候随机不到这种数的概率
就是1/2T,T的数字大了之后概率就很小了,几乎不可能了。对每个随机到的数我们直接判断他的三种情况,每种情况就是枚举
他的质因子,然后暴力计算需要操作的次数,最后取最小值就行了。
复杂度为O(T*(sqrt(max)+n*log(max)))。

 

代码:

 1 /*
 2 (神奇的随机算法)
 3 假设最大公约数为2时,每个数最多只需要操作一次就可以了,所以操作次数最多为n。所以需要操作次数≤1的数的数量≥n/2。
 4 一个数x操作次数≤1时候会变成x,x+1,x-1三种情况,所以我们可以随机一下需要操作次数≤1的数,这时候随机不到这种数的概率
 5 就是1/2T,T的数字大了之后概率就很小了,几乎不可能了。对每个随机到的数我们直接判断他的三种情况,每种情况就是枚举
 6 他的质因子,然后暴力计算需要操作的次数,最后取最小值就行了。
 7 复杂度为O(T*(sqrt(max)+n*log(max)))。
 8 ————————————————
 9 原文链接:https://blog.csdn.net/qq_41818939/java/article/details/104658566
10 */
11 #include<bits/stdc++.h>
12 using namespace std;
13 typedef long long ll;
14 mt19937 rng_32(chrono::steady_clock::now().time_since_epoch().count());
15 ll a[200005];
16 int n;
17 ll cal_ans(ll x)
18 {
19     ll ret=0;
20     for (int i=0;i<n;i++)
21     {
22         ll tmp=a[i]%x;
23         /*防止出现0
24         如果a[i]是0,那么tmp也是0
25         这样的话min(tmp,x-tmp)=0
26         但是这样肯定是错的,因为a[i]是0的话,是没有因子的
27         
28         */
29         if (a[i]!=tmp)
30         ret+=min(tmp,x-tmp);
31         else
32         ret+=x-tmp;
33     }
34     return ret;
35 }
36 //计算质因子
37 ll fac(ll x)
38 {
39     ll ret=1e18;
40     ll en=sqrt(x+1ll);
41     for(ll i=2;i<=en;i++)
42     {
43         if (x%i==0)
44         {
45             ret=min(ret,cal_ans(i));
46             while(x%i==0)
47             x/=i;
48             if (x==1)
49             break;
50         }
51     }
52     if (x>1)
53     ret=min(ret,cal_ans(x));
54     return ret;
55 }
56 int main()
57 {
58     //printf("%d\n",(0%5));
59     cin>>n;
60     for (int i=0;i<n;i++)
61     scanf("%I64d",&a[i]);
62     int T=10;
63     ll ans=1e18;
64     while (T--)
65     {
66         ll pos=rng_32()%n;
67         //处理三种情况
68         if (a[pos]>2)
69         ans=min(ans,fac(a[pos]-1ll));
70         ans=min(ans,fac(a[pos]));
71         ans=min(ans,fac(a[pos]+1ll));
72     }
73     cout<<ans;
74 }
View Code

 

posted @ 2020-04-30 10:27  kongbursi  阅读(147)  评论(0编辑  收藏  举报