「BZOJ2259」[Oibh] 新型计算机
Tim正在摆弄着他设计的“计算机”,他认为这台计算机原理很独特,因此利用它可以解决许多难题。
但是,有一个难题他却解决不了,是这台计算机的输入问题。新型计算机的输入也很独特,假设输入序列中有一些数字(都是自然数——自然数包括0),计算机先读取第一个数字S1,然后顺序向后读入S1个数字。接着再读一个数字S2,顺序向后读入S2个数字……依此类推。不过只有计算机正好将输入序列中的数字读完,它才能正确处理数据,否则计算机就会进行自毁性操作!
Tim现在有一串输入序列。但可能不是合法的,也就是可能会对计算机造成破坏。于是他想对序列中的每一个数字做一些更改,加上一个数或者减去一个数,当然,仍然保持其为自然数。使得更改后的序列为一个新型计算机可以接受的合法序列。
不过Tim还希望更改的总代价最小,所谓总代价,就是对序列中每一个数操作的参数的绝对值之和。
写一个程序:
从文件中读入原始的输入序列; 计算将输入序列改变为合法序列需要的最小代价;
向输出文件打印结果。
Input
输入文件包含两行,第一行一个正整数N,N<1 000 001。
输入文件第二行包含N个自然数,表示输入序列。
Output
仅一个整数,表示把输入序列改变为合法序列需要的最小代价,保证最小代价小于109。
Sample Input
4
2 2 2 2
Sample Output
1
这是一道很巧妙的构造建图的题
显然,由i->i+a[i]+1的边权为0 ,特别地,考虑i+a[i]+1>n+1 时,我们可以建i->n+1 (边权为a[i]+i-n),因为我们可以把它当作减小了a[i]+i-n这样一个操作
然后,由于可以进行操作使得位置左移/右移,所以每次在i->i-1 和i->i+1连边权为1的边,注意不要连重复
这样就将问题转换为最短路了 边数不超过3n
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
const int inf=0x3f3f3f3f;
int n,a[maxn],head[maxn],dis[maxn],cnt;
int l[maxn],r[maxn];
struct edge
{
int to,nxt,val;
}e[maxn<<2];
void add(int x,int y,int z)
{
e[++cnt].to=y;
e[cnt].nxt=head[x];
e[cnt].val=z;
head[x]=cnt;
}
struct point
{
int no,v;
bool operator <(const point &oth) const
{
return v>oth.v;
}
};
void dijkstra()
{
priority_queue <point> q;
for(int i=2;i<=n+1;i++) dis[i]=inf;
q.push((point){1,0});
while(!q.empty())
{
int u=q.top().no;
q.pop();
for(int i=head[u];i;i=e[i].nxt)
{
int to=e[i].to;
if(dis[to]>dis[u]+e[i].val)
{
dis[to]=dis[u]+e[i].val;
q.push((point){to,dis[to]});
}
}
}
}
int main()
{
freopen("computer.in","r",stdin);
freopen("computer.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
for(int j=i+a[i]+1;j<=n && !r[j];j++)
r[j]=1,add(j,j+1,1);
for(int j=i+1;j<=min(n,i+a[i]+1) && !l[j];j++)
l[j]=1,add(j,j-1,1);
if(i+a[i]+1>n+1)
add(i,n+1,i+a[i]-n);
else add(i,i+a[i]+1,0);
}
dijkstra();
printf("%d\n",dis[n+1]);
return 0;
}

博客围绕BZOJ2259新型计算机输入问题展开。该计算机输入独特,需将输入序列变为合法序列且更改总代价最小。通过构造建图,将问题转换为最短路问题,如i->i+a[i]+1边权为0等,边数不超3n,并给出输入输出示例。
379

被折叠的 条评论
为什么被折叠?



