CF 453B Little Pony and Harmony Chest

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

题目

给一串数字A,要求你找出一串数字B,满足

  • 这串数字两两互质
  • $sum leftlvert A[i]-B[i] ight vert$最小

$A[i]leqslant 30$,$nleqslant 100$

题解

因为1可以随便用,所以B[i]不会超过2倍A[i],否则不如直接用1

于是B[i]的取值范围是[1,59]

如果直接记录不能用的数字,直接开数组存不下((1<<59)*100)

如果存不能用的质因数就可以存下,打表发现质因数只有17个,所以可以记录下所有的状态((1<<17)*100)

那么可以写出转移方程

设dp[i][k]为从第i个数开始,已经用了的质因数有k(二进制压位)

$dp[i][k]=min (dp[i+1][k^fac[t]]+abs(t-A[i]))$

直接枚举状态和转移需要$100 imes 2^{17} imes 60$

其实这个$2^{17}$可以优化一下,t有m位是1的时候,可以省到$frac{1}{2^m}$

虽然还可以滚动优化,并且把记录改为char……

AC代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<cassert>
#define REP(i,a,b) for(register int i=(a); i<(b); i++)
#define REPE(i,a,b) for(register int i=(a); i<=(b); i++)
#define PERE(i,a,b) for(register int i=(a); i>=(b); i--)
using namespace std;
#define MAXN 107
#define MAXP 17
int ps[MAXP]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59};
unsigned fa[]={0,0,1,2,1,4,3,8,1,2,5,16,3,32,9,6,1,64,3,128,5,10,17,256,3,4,33,2,9,512,7,1024,1,18,65,12,3,2048,129,34,5,4096,11,8192,17,6,257,16384,3,8,5,66,33,32768,3,20,9,130,513,65536,7};
int n;
int arr[MAXN];
int dp[MAXN][1<<MAXP];
int go[MAXN][1<<MAXP];
int main() {
	scanf("%d", &n);
	REP(i,0,n) scanf("%d", &arr[i]);
	memset(dp,0x3f,sizeof(dp[0])*n);
	memset(dp[n],0,sizeof(dp[n]));
	PERE(i,n-1,0) {
		REPE(t,1,60) {
			unsigned qf=((1<<MAXP)-1)^fa[t];
			for(unsigned k=qf; k>0; k=(k-1)&qf) {
				int nd=dp[i+1][k|fa[t]]+abs(t-arr[i]);
				if(dp[i][k]>nd) {
					dp[i][k]=nd, go[i][k]=t;
				}
			}
			int nd=dp[i+1][fa[t]]+abs(t-arr[i]);
			if(dp[i][0]>nd) {
				dp[i][0]=nd, go[i][0]=t;
			}
		}
	}
	int now=0;
	REPE(i,0,n-1) {
		int nt=go[i][now];
		printf("%d%c", nt, " 
"[i==n-1]);
		now|=fa[nt];
	}
}
原文地址:https://www.cnblogs.com/sahdsg/p/12462732.html