Program
【题目描述】
你有一个正整数序列{Ai},大小为n,你还有2个变量x,y
执行以下程序:
x=1,y=0
While(true)
x+=Ax,y+=Ax
If x<=0 orx>n then exit
x-=Ax,y+=Ax
If x<=0 orx>n then exit
你的任务是得到一个序列A2,A3...An,
枚举i(1<=i<=n-1),令A1等于i,输出上面那个程序y的值,如果程序陷入死循环输出-1
【输入格式】
第一行n
第二行n-1个整数a2,a3,...,an
【输出格式】
输出n-1行,为枚举每个i得到的结果
【输入输出样例】
Input1
4
2 4 1
Output1
3
6
8
Input2
3
1 2
Output2
-1
-1
【样例解释】
In the firstsample
1 For i = 1, xbecomes and ybecomes 1 + 2 = 3.
2 For i = 2, xbecomes and ybecomes 2 + 4 = 6.
3 For i = 3, xbecomes and ybecomes 3 + 1 + 4 = 8.
【数据约定】
40%数据 n<=1000
100%数据2<=n<=10^5 1<=ai<=10^9
【解法一】
想到 循环到某个数后,后面出现的数一定相同。所以就想到构图,如果i点能连接连接到j点,则用i连接到j点。并且把j的值传递给i值,这样,到一个点后,我们就能快速知道到结束时所输出的值为多少,整体时间复杂度约为 o(n)
【代码一】
#include<cstdlib>
#include<cstdio>
#include<iomanip>
#include<iostream>
#include<cstring>
using namespace std;
int i,j,k,m,n,o,p,js,jl,kk;
struct tu
{
int pp;
int pj;
};
int a[100001];
int b[100001]={0};
tu f[100001];
int build(int k,int u)
{
if(u==0)if(f[k].pp!=0)return(f[k].pp);
if(u==1)if(f[k].pj!=0)return(f[k].pj);
if(b[k]==1)
{
return(-1);
}
b[k]=1;
if(u==0)
{
if(k+a[k]>n)
{
f[k].pp=a[k];
return(a[k]);
}
else
{
kk=build(k+a[k],1);
if(kk==-1)f[k].pp=-1;
else f[k].pp=kk+a[k];
}
return(f[k].pp);
}
else
{
if(k-a[k]<=0)
{
f[k].pj=a[k];
return(a[k]);
}
else
{
kk=build(k-a[k],0);
if(kk==-1)f[k].pj=-1;
else f[k].pj=kk+a[k];
}
return(f[k].pj);
}
}
int main()
{
FILE *fin,*fout;
fin=fopen("program.in","rb");
fout=fopen("program.out","wb");
fscanf(fin,"%d",&n);
for(int i=2;i<=n;i++)fscanf(fin,"%d",&a[i]);
for(i=2;i<=n;i++)
{
k=i;
b[a[i]]=1;
memset(b,0,sizeof(b));
build(k,0);
memset(b,0,sizeof(b));
build(k,1);
}
for(int i=1;i<=n-1;i++)
{
if(f[1+i].pj>0)fprintf(fout,"%d\n",f[1+i].pj+i);
else fprintf(fout,"-1\n");
}
fclose(fin);
fclose(fout);
}
【解法二】
一个点按是加一个数得到还是减一个数得到的性质拆成2份,这样发现一个点最多一个出度
那么就形成了若干颗树和若干个环。枚举A1=i连出去的情况,是在树上走还是走到环里。记忆化搜索即可。
【代码二】
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<ctime>
using namespace std;
#define REP(i,n) for(i=0;i<n;++i)
#define FOR(i,j,k) for(i=j;i<=k;++i)
#define FORD(i,j,k) for(i=j;i>=k;--i)
#define met(i,j) memset(i,j,sizeof(i))
#define fo(i,j) for(typeof(j.begin()) i=j.begin();i!=j.end();++i)
#define PB push_back
#define MK make_pair
#define sz size()
const int inf=2147483647;
typedef pair<int, int> PII;
typedef long long LL;
typedef unsigned long long ULL;
FILE*fin,*fout;
#define N 400005
int bj,n,a[N],mark[N];
LL f[N];
void init()
{
int i;
fscanf(fin,"%d",&n);
FOR(i,2,n)
{
fscanf(fin,"%d",a+i);
}
}
LL dfs(int v)
{
int _x,x;LL temp;
if(mark[v]==1)return f[v]=-1;
if(v==1){bj=1;return 0;}
if(f[v]!=0)return f[v];
mark[v]=1;
_x=x=v/2+1;
if(v%2==0)
{
x+=a[x];
if(x<=0||x>n)temp=0;else temp=dfs(x*2-1);
}else
{
x-=a[x];
if(x<=0||x>n)temp=0;else temp=dfs(x*2-2);
}
mark[v]=0;
if(temp==-1)return f[v]=-1;else return f[v]=temp+a[_x];
}
void work()
{
int i;LL temp;
FOR(i,1,n-1)
{
f[0]=f[1]=0;
a[1]=i;bj=0;
temp=dfs(0);
if(bj)temp+=dfs(1);
fprintf(fout,"%I64d\n",temp);
}
}
int main()
{
fin=fopen("program.in","rb");
fout=fopen("program.out","wb");
init();
work();
}