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();
    //}
}
原文地址:https://www.cnblogs.com/nonames/p/12417796.html