在贴吧上看到了这道题,恰好最近在学相关的东西,觉得比较有意思就去做了。
第一眼看上去比较像搜索,其实是道状压DP。我简单讲一下思路:
首先明确,不管之前取了什么数,取1必定满足所有的数之间互质。而且如果出现最优的可以是1或者其他,那么1一定是更优的
再思考,对于每个读入的数,合适的范围必定是[1,2*a[i]-2]
而且a[i]<=30,这就很好搞了。
我们表出来所有小于58的素数,把每个数有哪几个素因子二进制表示出来。然后然后如果满足前一个状态&这个数,如果满足的话就更新条件。
1 //Vijos 1921 2 //by Cydiater 3 //2016.8.25 4 #include <iostream> 5 #include <cstdio> 6 #include <cstring> 7 #include <ctime> 8 #include <queue> 9 #include <map> 10 #include <cmath> 11 #include <algorithm> 12 #include <iomanip> 13 #include <string> 14 #include <cstdlib> 15 using namespace std; 16 #define ll long long 17 #define up(i,j,n) for(int i=j;i<=n;i++) 18 #define down(i,j,n) for(int i=j;i>=n;i--) 19 const int MAXN=1<<16|1; 20 const int oo=0x3f3f3f3f; 21 inline int read(){ 22 char ch=getchar();int x=0,f=1; 23 while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();} 24 while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} 25 return x*f; 26 } 27 int prime[16]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53}; 28 int a[MAXN],N,p[60],f[105][MAXN],ans=oo; 29 namespace solution{ 30 inline int col(int num){ 31 int tmp=0; 32 up(i,0,15)if(num%prime[i]==0) 33 tmp|=(1<<i); 34 return tmp; 35 } 36 void init(){ 37 N=read(); 38 up(i,1,N)a[i]=read(); 39 up(i,1,58)p[i]=col(i); 40 } 41 void dp(){ 42 up(i,0,N)up(S,0,(1<<16)-1)f[i][S]=oo; 43 f[0][0]=0; 44 up(i,1,N)up(S,0,(1<<16)-1)if(f[i-1][S]!=oo){ 45 f[i][S]=min(f[i][S],f[i-1][S]+abs(1-a[i])); 46 if(a[i]==1)continue; 47 up(j,2,2*a[i]-2)if(!(p[j]&S))f[i][S|p[j]]=min(f[i][S|p[j]],f[i-1][S]+abs(a[i]-j)); 48 } 49 } 50 void output(){ 51 up(S,0,(1<<16)-1)ans=min(ans,f[N][S]); 52 cout<<ans<<endl; 53 } 54 } 55 int main(){ 56 //freopen("input.in","r",stdin); 57 using namespace solution; 58 init(); 59 dp(); 60 output(); 61 return 0; 62 }
时间: 2024-10-21 08:58:37