在贴吧上看到了这道题,恰好最近在学相关的东西,觉得比较有意思就去做了。
第一眼看上去比较像搜索,其实是道状压DP。我简单讲一下思路:
首先明确,不管之前取了什么数,取1必定满足所有的数之间互质。而且如果出现最优的可以是1或者其他,那么1一定是更优的
再思考,对于每个读入的数,合适的范围必定是[1,2*a[i]-2]
而且a[i]<=30,这就很好搞了。
我们表出来所有小于58的素数,把每个数有哪几个素因子二进制表示出来。然后然后如果满足前一个状态&这个数,如果满足的话就更新条件。
//Vijos 1921 //by Cydiater //2016.8.25 #include <iostream> #include <cstdio> #include <cstring> #include <ctime> #include <queue> #include <map> #include <cmath> #include <algorithm> #include <iomanip> #include <string> #include <cstdlib> using namespace std; #define ll long long #define up(i,j,n) for(int i=j;i<=n;i++) #define down(i,j,n) for(int i=j;i>=n;i--) <<|; const int oo=0x3f3f3f3f; inline int read(){ ,f=; ;ch=getchar();} +ch-';ch=getchar();} return x*f; } ]={,,,,,,,,,,,,,,,}; ],f[][MAXN],ans=oo; namespace solution{ inline int col(int num){ ; up(i,,)) tmp|=(<<i); return tmp; } void init(){ N=read(); up(i,,N)a[i]=read(); up(i,,)p[i]=col(i); } void dp(){ up(i,,N)up(S,,(<<)-)f[i][S]=oo; f[][]=; up(i,,N)up(S,,(<<)-)][S]!=oo){ f[i][S]=min(f[i][S],f[i-][S]+abs(-a[i])); )continue; up(j,,*a[i]-)][S]+abs(a[i]-j)); } } void output(){ up(S,,(<<)-)ans=min(ans,f[N][S]); cout<<ans<<endl; } } int main(){ //freopen("input.in","r",stdin); using namespace solution; init(); dp(); output(); ; }