test20181018 B君的第三題
阿新 • • 發佈:2018-10-21
fclose splay efi mes memset ots con names 規模 。
對於30% 的數據,滿足\(1 \leq n \leq 4\)。
對於另30% 的數據,滿足\(1 \leq a_i \leq 10\)。 ,上界十分不緊。
題意
B 君的第三題(shenyang)
題目描述
客似雲來,萬裏無雲
B 君得到了一個數組\(\{a_1,a_2,\dots,a_n\}\)。
B 君想通過修改讓數組中個每對數都互質。
每次使一個數+1 或者-1 的代價是1。
不能將\(a_i\) 修改為0 或者負數。
問至少多少代價才可以讓所有數兩兩互質。
輸入格式
第一行一個整數n。
第二行n 個整數\(a_i\),表示數組初始值。
輸出格式
一行一個數表示答案。
樣例輸入
5
2 4 6 8 10
樣例輸出
4
樣例解釋
修改為2, 3, 5, 7, 11。
數據規模與約定
對於100% 的數據,滿足\(1 \leq n \leq 100, 1 \leq a_i \leq 30\)
對於30% 的數據,滿足\(1 \leq n \leq 4\)。
對於另30% 的數據,滿足\(1 \leq a_i \leq 10\)。
分析
因為\(a_i \leq 30\),1跟所有數互質,所以往下最多改到1,往上最多改到59,所以每個數所含質因數是固定的。
考慮dp,用\(f(i,s)\)表示前i個數改動至只含s集合中的質因數且兩兩互質所需最小代價,轉移方程為:
\[
枚舉i改成x,x所含質因數集合為s \枚舉從原來的含k的集合轉移過來,其中k與s沒有交集 \\
f(i,k∨s)=\min_{x=1}^{59}f(i-1,k)+|a_i-x|
\]
時間復雜度\(O(n \cdot 59 \cdot 2^{17})\)
代碼
#include<cstdlib> #include<cstdio> #include<cmath> #include<cstring> #include<iostream> #include<string> #include<vector> #include<list> #include<deque> #include<stack> #include<queue> #include<map> #include<set> #include<bitset> #include<algorithm> #include<complex> #define rg register #define il inline #define co const #pragma GCC optimize ("O0") using namespace std; template<class T> il T read() { T data=0; int w=1; char ch=getchar(); while(!isdigit(ch)) { if(ch==‘-‘) w=-1; ch=getchar(); } while(isdigit(ch)) data=10*data+ch-‘0‘,ch=getchar(); return data*w; } template<class T> il T read(T&x) { return x=read<T>(); } typedef long long ll; const int INF=0x7fffffff; int p[17]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59}; il int bit(rg int x) { rg int s=0; for(rg int i=0;i<17;++i) if(x%p[i]==0) s|=(1<<i); return s; } int b[60]; const int MAXN=107; int f[MAXN][1<<17]; int main() { freopen("shenyang.in","r",stdin); freopen("shenyang.out","w",stdout); memset(f,0x3f,sizeof f); f[0][0]=0; rg int n=read<int>(); for(rg int i=1;i<=59;++i) b[i]=bit(i); for(rg int i=1;i<=n;++i) { rg int a=read<int>(); for(rg int j=1;j<=59;++j) { rg int ub=((1<<17)-1)^b[j]; for(rg int k=ub;;--k&=ub) { f[i][k|b[j]]=min(f[i][k|b[j]],f[i-1][k]+abs(a-j)); if(k==0) break; } } } rg int ans=INF,up=(1<<17)-1; for(rg int i=0;i<=up;++i) ans=min(ans,f[n][i]); printf("%d\n",ans); // fclose(stdin); // fclose(stdout); return 0; }
test20181018 B君的第三題