天天看点

cf 状压dp Little Pony and Harmony Chest

http://codeforces.com/problemset/problem/453/B

cf机子跑的真快,4亿的复杂度都可以跑过,最多也就1s多,给的4s

当时写的时候不太敢写,觉得4e8了==,况且自己还要递归打印

于是各种优化,300多ms就跑完了,给的4s

dp[i][j]

前i个数,对应的所存在的素数的状态为j时,差值的最小值 (对应的b序列最多是1到58,就是16个素数,二进制表示,每个素数的存在,1<<16)

优化1:

当n大于16时,一定会有n-16个1,因为最多有16个互质的数,剩下的就只能是1了

贪心一下,先排序,从大到小,每个对应的ai,初始化为1

只需处理前16个ai,所以n的范围就缩小为1到16

n = min(16,n)

优化2:

下一个bi一定不能存在约数,与素数状态为j时,其中的素数不互质

ans[i][j]:状态为i时,b为j

ans[i][j]=-1代表素数不互质,否则储存加进j后的状态t

优化3:

dp[i][k]是由dp[i-1][t]的状态转化来的,dp[i-1][t]必须存在才行

即dp[i-1][t]!=inf

最后递归打印就好了

代码如下

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <climits>
#include <string>
#include <vector>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <sstream>
#include <cctype>
using namespace std;
typedef long long ll;
typedef pair<int ,int> pii;
#define MEM(a,b) memset(a,b,sizeof a)
#define CLR(a) memset(a,0,sizeof a);
const int inf = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
//#define LOCAL
struct node
{
	int pos;
	int x;
	int y;
}a[101];
int ans[1<<17][60];
int dp[20][1<<17];
int v[40];
int vis[100];
int cnt = 0;
int n=16;
bool cmp(node a,node b){
	return a.x > b.x;
}
void init(){
	for(int i=0;i<(1<<16);i++){
		for(int j=1;j<=59;j++){
			int t = i;
			int flag = 1;
			for(int k=0;k<cnt;k++){
				if((i & (1<<k)) && j%v[k]==0){
					ans[i][j]=-1;
					flag = 0;
					break;
				}
				else if(j%v[k]==0){
					t |= (1<<k);
				}
			}
			if(flag){
				ans[i][j]=t;
			}
		}
	}
}
void dfs(int l,int x,int nmin){
	if(l==0)return ;
	int res = 1;
	for(int i=0;i<(1<<16);i++){
		for(int j=1;j<=59;j++){
			if(ans[i][j]==x && dp[l-1][i]+fabs(j-a[l].x)==nmin){
				dfs(l-1,i,dp[l-1][i]);
				res = j;
				goto end;
			}
		}
	}
	end:
	a[l].y = res;
	return;
}
int main()
{
#ifdef LOCAL
	freopen("in.txt", "r", stdin);
//	freopen("out.txt","w",stdout);
#endif
	for(int i=2;i<=58;i++){
		if(!vis[i]){
			v[cnt++]=i;
			for(int j=i*2;j<=58;j+=i){
				vis[j]=1;
			}
		}
	}
	init();
	int N;scanf("%d",&N);
	for(int i=1;i<=N;i++){
		scanf("%d",&a[i].x);
		a[i].pos = i,a[i].y = 1;
	}
	sort(a+1,a+1+N,cmp);
	n = min(n,N);
	MEM(dp,inf);
	dp[0][0]=0;
	for(int i=1;i<=n;i++){
		for(int j=0;j<(1<<16);j++){
			if(dp[i-1][j]!=inf){
				for(int k=1;k<=59;k++){
					if(ans[j][k]!=-1){
						dp[i][ans[j][k]]=min(dp[i][ans[j][k]],dp[i-1][j]+(int)fabs(k-a[i].x));
					}
				}
			}
		}
	}
	int ans = inf;
	int x;
	for(int j=0;j<(1<<16);j++){
		if(ans > dp[n][j]){
			ans = dp[n][j];
			x = j;
		}
	}
	dfs(n,x,ans);
	for(int i=1;i<=N;i++){
		for(int j=1;j<=N;j++){
			if(i==a[j].pos){
				printf("%d ",a[j].y);
			}
		}
	}
	return 0;
}