题意:给出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(); //} }