SERC 2013 A: Beautiful Mountains

http://acm.hunnu.edu.cn/online/?action=problem&type=show&id=11441

6482 - Beautiful Mountains

Time limit: 3.000 seconds
A:   Beautiful Mountains
Paco  loves  playing  with stacks of blocks.  He  likes to  pretend  that  they are  mountains, 
and he loves making his own terrain. Lately, he’s been restricting himself to a particular 
way  of  rearranging  the  blocks.  He  puts  all  of  his  stacks  of  blocks  into  a  straight  line. 
Then, he only changes the arrangement one block at a time. Paco does this by finding 
two adjacent stacks of blocks and moving one block from one stack to the other.
Paco has made all sorts of arrangements of his ‘mountains’ using this technique. Now he 
has decided to make his most beautiful arrangements yet. Paco finds a mountain range 
beautiful if, for every pair of mountains, the distance between the two mountains is a 
prime number (that's  every pair, not just every adjacent pair). A mountain range with a 
single stack is beautiful by default. Paco considers a stack of blocks to be a mountain if it 
has at least one block.
1 0 1
0
1 0 1 3
1
1
0
2
2
3
This diagram shows an initial configuration of the blocks, and a way  to make two stacks, 
at a distance of three apart, with 13 moves. However, with only 6 moves, Paco can make 
a beautiful arrangement with 3 stacks:
1 0 1
0
0 1 1 1
0
0
1
0
0
3 2
5
2013 ACM ICPC Southeast USA Regional Programming Contest
Page 2 of 16    2 November, 2013



一顿乱优化。。。。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long int LL;
const int maxn=30030;

int n;
bool isprime[maxn];
LL moutain[maxn];
LL leftcost[maxn],rightcost[maxn],sum[maxn],prime[maxn],pr=0;

void getPRIME()
{
    int d;
    memset(isprime,1,sizeof(isprime));
    for(int i=2;i<=200;i+=d)
    {
        if(i==2) d=1; else d=2;
        if(isprime[i])
        {
            for(int j=i+i;j<maxn;j+=i) isprime[j]=false;
        }
    }
    for(int i=2;i<maxn;i++)
    {
        if(isprime[i]) prime[pr++]=i;
    }
}

int main()
{
    getPRIME();
    while(scanf("%d",&n)!=EOF&&n)
    {
        leftcost[0]=rightcost[n]=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%I64d",moutain+i);
            sum[i]=sum[i-1]+moutain[i];
            leftcost[i]=leftcost[i-1]+sum[i-1];
        }
        if(sum[n]==0) {puts("0");continue;}
        for(int i=n-1;i>=1;i--)
        {
            rightcost[i]=rightcost[i+1]+sum[n]-sum[i];
        }

        LL mincost=132222222000LL;
        for(int i=1;i<=n;i++)
        {
            ///只有1堆
            LL costP,toleft,toright; int from,to,m;
            mincost=min(mincost,leftcost[i]+rightcost[i]);
            for(int j=0;prime[j]+i<=n;j++)
            {
                LL costP=0;

                bool flag=false;
                ///只有4堆 2 + P + 2
                if(prime[j]==3&&i+prime[j]+4<=n)
                {
                    costP=leftcost[i]+rightcost[i+prime[j]+4];
                    int m=(2*i+4+prime[j])>>1;
                    from=m,to=i+2;
                    toleft=rightcost[to]-rightcost[from]-(from-to)*(sum[n]-sum[from]);
                    from=m+1,to=prime[j]+i+2;
                    toright=leftcost[to]-leftcost[from]-(to-from)*sum[from-1];

                    if(costP+toleft+toright+moutain[i+1]+moutain[i+prime[j]+3]<mincost)
                    {
                        mincost=costP+toleft+toright+moutain[i+1]+moutain[i+prime[j]+3];
                        flag=true;
                    }
                }
                if(flag) continue;

                ///只有3堆
                if(isprime[prime[j]+2]&&i+prime[j]+2<=n)
                {
                    costP=leftcost[i]+rightcost[i+prime[j]+2];
                    ///左边相隔为2右边相隔为P
                    m=(2*i+4+prime[j])>>1;
                    from=m,to=i+2;
                    toleft=rightcost[to]-rightcost[from]-(from-to)*(sum[n]-sum[from]);
                    from=m+1,to=i+prime[j]+2;
                    toright=leftcost[to]-leftcost[from]-(to-from)*sum[from-1];
                    if(mincost>costP+toleft+toright+moutain[i+1])
                    {
                        flag=true;
                        mincost=costP+toleft+toright+moutain[i+1];
                    }
                    ///左边间隔为P右边间隔为2
                    m=(2*i+prime[j])>>1;
                    from=m,to=i;
                    toleft=rightcost[to]-rightcost[from]-(from-to)*(sum[n]-sum[from]);
                    from=m+1,to=i+prime[j];
                    toright=leftcost[to]-leftcost[from]-(to-from)*sum[from-1];
                    if(mincost>costP+toleft+toright+moutain[i+prime[j]+1])
                    {
                        flag=true;
                        mincost=costP+toleft+toright+moutain[i+prime[j]+1];
                    }
                }

                if(flag) continue;
                ///只有两堆而且相隔P
                costP=leftcost[i]+rightcost[i+prime[j]];
                int m=(2*i+prime[j])>>1;
                int from=m,to=i;
                LL toleft=rightcost[to]-rightcost[from]-(from-to)*(sum[n]-sum[from]);
                from=m+1,to=i+prime[j];
                LL toright=leftcost[to]-leftcost[from]-(to-from)*sum[from-1];

                if(mincost>costP+toleft+toright) mincost=costP+toleft+toright;
            }
        }
        printf("%I64d\n",mincost);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值