http://acm.hunnu.edu.cn/online/?action=problem&type=show&id=11441
6482 - Beautiful MountainsTime limit: 3.000 seconds |
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;
}