good array(数论+随机算法)
题意:给出n个数(1<=ai<=1012),可以对这组数进行两种操作加一或减一。问最少要几次操作可以使这组数得gcd>1。
解法:我们先假设我们已经知道了素因子是什么,假设其为p,所以有一个很明显的贪心策略,就是每一个数只会变成与它相邻的两个是p的倍数的正整数,所以我们就可以得到一个O(n)的贪心策略。先把2和3跑一遍(因为这两个最容易成为答案,
然后就是随机了,随机抽取序列中的一个数,令其为x,然后把x分解质因数,对它的每一个质因数都跑一遍,然后再这么操作x−1和x+1,这样的话算法错误的概率是1/2,然后重新随机。这样随机 20 次之后,程序错误的概率就是1/220.
#include<bits/stdc++.h>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <string>
#include <stdio.h>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <string.h>
#include <vector>
typedef long long ll ;
#define int ll
#define mod 1000000007
#define gcd __gcd
#define rep(i , j , n) for(int i = j ; i <= n ; i++)
#define red(i , n , j) for(int i = n ; i >= j ; i--)
#define ME(x , y) memset(x , y , sizeof(x))
//ll lcm(ll a , ll b){return a*b/gcd(a,b);}
ll quickpow(ll a , ll b){ll ans=1;while(b){if(b&1)ans=ans*a%mod;b>>=1,a=a*a%mod;}return ans;}
//int euler1(int x){int ans=x;for(int i=2;i*i<=x;i++)if(x%i==0){ans-=ans/i;while(x%i==0)x/=i;}if(x>1)ans-=ans/x;return ans;}
//const int N = 1e7+9; int vis[n],prime[n],phi[N];int euler2(int n){ME(vis,true);int len=1;rep(i,2,n){if(vis[i]){prime[len++]=i,phi[i]=i-1;}for(int j=1;j<len&&prime[j]*i<=n;j++){vis[i*prime[j]]=0;if(i%prime[j]==0){phi[i*prime[j]]=phi[i]*prime[j];break;}else{phi[i*prime[j]]=phi[i]*phi[prime[j]];}}}return len}
#define SC scanf
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define pii pair<int,int>
#define fi first
#define se second
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
using namespace std;
const int N = 1e6+100;
const int maxn = 2e5+9;
int n ;
int a[maxn] , p[maxn], len;
void euler1(int x){
len = 0 ;
for(int i = 2 ; i * i <= x ; i++){
if(x % i == 0){
p[++len] = i ;
while(x % i == 0){
x /= i ;
}
}
}
if(x > 1) p[++len] = x ;
}
int work(int x){
int ans = 0 ;
rep(i , 1 , n){
if(a[i] < x){
ans += x - a[i];
if(ans >= n){
break;
}
continue;
}
int fron = a[i] / x ;
int bac = (fron+1)*x;
fron *= x ;
ans += min(a[i]-fron , bac - a[i]);
if(ans >= n){
break;
}
}
return ans ;
}
void solve(){
clock_t begin , end;
begin = clock();
mt19937 rnd(time(NULL));
cin >> n ;
rep(i , 1 , n){
cin >> a[i];
}
int ans = n ;
int num = 0 ;
rep(i , 1 , n){
if(a[i]&1){
num++;
}
}
ans = min(ans , num);
num = 0;
rep(i , 1 , n){
if(a[i] == 1){
num += 2 ;
}else if(a[i] % 3){
num++;
}
}
ans = min(ans , num);
while(1){
int x = rnd()%n + 1;
euler1(a[x]);
rep(i , 1 , len){
ans = min(ans , work(p[i]));
}
euler1(a[x]-1);
rep(i , 1 , len){
ans = min(ans , work(p[i]));
}
euler1(a[x]+1);
rep(i , 1 , len){
ans = min(ans , work(p[i]));
}
end = clock();
if((end - begin)*1.0/CLOCKS_PER_SEC > 2.0){
break;
}
}
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(false);
//cin.tie(0); cout.tie(0);
//int t ;
//cin >> t ;
//while(t--){
solve();
//}
}
cf官方题解:
#include<bits/stdc++.h>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <string>
#include <stdio.h>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <string.h>
#include <vector>
typedef long long ll ;
#define int ll
#define mod 1000000007
#define gcd __gcd
#define rep(i , j , n) for(int i = j ; i <= n ; i++)
#define red(i , n , j) for(int i = n ; i >= j ; i--)
#define ME(x , y) memset(x , y , sizeof(x))
//ll lcm(ll a , ll b){return a*b/gcd(a,b);}
ll quickpow(ll a , ll b){ll ans=1;while(b){if(b&1)ans=ans*a%mod;b>>=1,a=a*a%mod;}return ans;}
//int euler1(int x){int ans=x;for(int i=2;i*i<=x;i++)if(x%i==0){ans-=ans/i;while(x%i==0)x/=i;}if(x>1)ans-=ans/x;return ans;}
//const int N = 1e7+9; int vis[n],prime[n],phi[N];int euler2(int n){ME(vis,true);int len=1;rep(i,2,n){if(vis[i]){prime[len++]=i,phi[i]=i-1;}for(int j=1;j<len&&prime[j]*i<=n;j++){vis[i*prime[j]]=0;if(i%prime[j]==0){phi[i*prime[j]]=phi[i]*prime[j];break;}else{phi[i*prime[j]]=phi[i]*phi[prime[j]];}}}return len}
#define SC scanf
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define pii pair<int,int>
#define fi first
#define se second
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
using namespace std;
const int N = 1e6+100;
const int MX = 1e6+2 ;
const int maxn = 2e5+9;
int n , ans = maxn;
int a[maxn] , p[maxn], len;
bool chk[MX];
set<int>can;
vector<int>pr;
mt19937_64 mt(chrono::steady_clock::now().time_since_epoch().count());//随机数
void init(){//为分解质因数作准备
for(int i = 2 ; i < MX ; i++){
if(!chk[i]){
pr.push_back(i);
for(int j = i ; j < MX ; j += i){
chk[j] = true;
}
}
}
}
void add_prime(int u){//分解质因数
for(int &v :pr){
if(u % v == 0){
can.insert(v);
while(u % v == 0){
u /= v ;
}
}
}
if(u > 1){
can.insert(u);
}
}
int work(int u){//贪心
int ret = 0 ;
rep(i , 1 , n){
int add = (a[i] < u ? u - a[i] : min(a[i]%u , u - a[i]%u));
ret = min(n , ret + add);
}
return ret ;
}
void solve(){
init();
cin >> n ;
vector<int>per;
rep(i , 1 , n){
cin >> a[i];
per.push_back(i);
}
shuffle(per.begin() , per.end() , mt);
for(int i = 0 ; i < 100 && i < (int)per.size() ; i++){
int u = per[i];
add_prime(a[u]);
add_prime(a[u]+1);
if(a[u] > 1){
add_prime(a[u]-1);
}
}
for(int v : can){
ans = min(ans , work(v));
}
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
//cin.tie(0); cout.tie(0);
//int t ;
//cin >> t ;
//while(t--){
solve();
//}
}

浙公网安备 33010602011771号