您的位置:首页 > 其它

Codeforces Round #174 (Div. 1) B. Cow Program(动态规划+记忆化搜索)

2013-05-16 19:24 585 查看

题目大意

Farmer John 给了他的 cows 一个程序玩。这个程序有两个整形变量 x 和 y,并且在一个正数序列 a1 a2 a3,...,an (2≤n≤2*105,1≤ai≤109)中执行以下操作:

1、初始化 x=1, y=0,如果经过任何步骤之后 x≤0 或者 x>n,程序立刻停止运行

2、x 和 y 同时增加 ax(注意:增加的值是 a 序列中的第 x 个,也就是 ax)

3、x 减小 ax,y 增加 ax

4、程序重复执行步骤 2 和步骤 3 直至终止

现在给了你 a2 a3 a4,...,an,程序总共运行了 n-1 次,第 i(1≤i≤n-1) 次运行的时候 a1=i,问程序停止运行之后 y 是多少?如果不能停止运行,输出 -1

做法分析

观察步骤 2 和步骤 3,可以知道:

1、y 是记录的 x 变化的值,程序终止只和 x 有关,与 y 无关

2、步骤 2 使得 x 增加,步骤 3 使得 x 减小

3、当 x 为 1 的时候,下一步必然是执行步骤 2(因为上面的第 2 条规律),永远不可能停止,输出 -1

4、当 x 表示的值重复出现并且下一步执行的步骤相同时,程序必然陷入一个循环中,永远不可能停止,输出 -1

想到了上面的四个规律,这道题目就简单了

定义 f(i, j) 表示:当 x=i 的时候,到程序终止,y 会加上的值是多少,那么,状态就是这样转移的:

f(i, 0)=f(i+ai, 1)+ai:这一步该执行步骤 2

f(i, 1)=f(i-ai, 0)+ai:这一步该执行步骤 3

在计算的过程中,如果 i+ai 或者 i-ai 超过范围,必然是程序终止了;如果 i=1 或者 i 是之前某个经过的节点,必然陷入死循环

那么每次 a1 变化的时候,直接输出 a1+f(1+a1, 1) 就行了

参考代码

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

using namespace std;

typedef long long LL;
const int N=200006;
const LL INF=((1LL)<<60);

LL f
[2];
bool vs
[2];
int n, A
;

LL DP(int x, int dir)
{
if(x>n || x<=0) return 0;
if(x==1) return INF;
if(f[x][dir]!=-1) return f[x][dir];
if(vs[x][dir]) return INF;
vs[x][dir]=1;
LL res;
if(dir==0) res=DP(x+A[x], 1);
else res=DP(x-A[x], 0);
if(res!=INF) f[x][dir]=(LL)A[x]+res;
else f[x][dir]=INF;
return f[x][dir];
}

int main()
{
scanf("%d", &n);
for(int i=2; i<=n; i++) scanf("%d", &A[i]);
memset(f, -1, sizeof f);
memset(vs, 0, sizeof vs);
for(int i=2; i<=n; i++)
{
if(f[i][0]==-1) f[i][0]=DP(i, 0);
if(f[i][1]==-1) f[i][1]=DP(i, 1);
}
for(int i=1; i<n; i++)
{
if(f[1+i][1]==INF) printf("-1\n");
else printf("%I64d\n", i+f[1+i][1]);
}
return 0;
}


B. Cow Program

题目链接 & AC通道

Codeforces Round #174 (Div. 1) B. Cow Program
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: