1. 程式人生 > >test20181018 B君的第三題

test20181018 B君的第三題

fclose splay efi mes memset ots con names 規模

題意

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君的第三題