您的位置:首页 > 其它

Codeforces 623 B. Array GCD

2016-02-06 14:04 344 查看
传送门:

http://codeforces.com/contest/623/problem/B

题意:

有n个数,你可以花费i*a去删除长度i的线段,也可以花费B去让一个数+-1,但是删除操作只能进行一次,+-1对一个数也只能操作一次

并且删除操作不能删除所有的数

问你最小花费多少,可以使得剩下的数的gcd不等于1

题解:

很显然,因为不能删除完,所以必然第一个数和最后一个数会剩下来

所以我们暴力枚举第一个数和最后一个数的质因子就好了

然后开始跑dp

dp[i][0,1,2] 分别表示子串未开始,开始了,取完了的状态下达到目标所需要的最低花费,然后dp就可以了!!

code:

[code]#include <cstdio>
#include <algorithm>
#include <set>

using namespace std;

set<int> fac;

void factor(int x)
{
    for (int i = 2; i * i <= x; ++i)
    {
        if (x % i == 0)
        {
            fac.insert(i);
            while (x % i == 0)
                x /= i;
        }
    }
    if (x > 1)
        fac.insert(x);
}

int n, a, b;
int p[1000000];
long long dp[1000001][3];

long long check(int v)
{
    dp[0][0] = 0;
    dp[0][1] = dp[0][2] = 1e18;
    for (int i = 0; i < n; ++i)
    {
        dp[i + 1][0] = dp[i + 1][1] = dp[i + 1][2] = 1e18;
        if (p[i] % v == 0)
        {
            dp[i + 1][0] = dp[i][0];
            dp[i + 1][2] = min(dp[i][1], dp[i][2]);
        }
        else if ((p[i] + 1) % v == 0 || (p[i] - 1) % v == 0)
        {
            dp[i + 1][0] = dp[i][0] + b;
            dp[i + 1][2] = min(dp[i][1], dp[i][2]) + b;
        }
        dp[i + 1][1] = min(dp[i][0], dp[i][1]) + a;
    }
    return min({dp
[0], dp
[1], dp
[2]});
}

int main()
{
    scanf("%d %d %d", &n, &a, &b);
    for (int i = 0; i < n; ++i)
        scanf("%d", &p[i]);
    for (int u: {-1, 0, 1})
        for (int v: {p[0], p[n - 1]})
            factor(u + v);
    long long ans = 1e18;
    for (int v: fac)
        ans = min(ans, check(v));
    printf("%I64d\n", ans);
    return 0;
}


附上另一种写法(原理一样,只不过就用了3个状态去表示):

并且体会一下vector的去重方法

[code]#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>

using namespace std;

typedef long long LL;

const LL INF=10000000000000000LL;
const int N=1000000+10;

vector<int>V;
int n,x
;
LL a,b;
void MakePrime(int x)
{
    int Max=int(sqrt((double)x));
    for (int i=2;i<=Max;i++){
        if (x%i==0){
            V.push_back(i);
            while (x%i==0)x/=i;
        }
    }
    if (x>1)V.push_back(x);
}
LL Solve(int p)
{
    LL s1=0,s2=0,s3=0;
    for (int i=1;i<=n;i++){
        LL Now=INF;
        if (x[i]%p==0)Now=0;
        else if ((x[i]-1)%p==0 || (x[i]+1)%p==0)Now=b;
        s1=min(s1+Now,INF);s2=min(s1,s2+a);s3=min(s2,s3+Now);
    }
    return s3;
}
int main()
{
    cin>>n>>a>>b;
    for (int i=1;i<=n;i++)scanf("%d",&x[i]);
    for (int i=-1;i<=1;i++){
        MakePrime(x[1]+i);
        MakePrime(x
+i);
    }
    sort(V.begin(),V.end());
    V.erase(unique(V.begin(),V.end()),V.end());

    LL Ans=INF;
    for (int i=0;i<V.size();i++){
        Ans=min(Ans,Solve(V[i]));
    }
    cout<<Ans<<endl;
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: