首先观察发现,如果有长度限制的话,最长不会超过最大值得两倍。首先有长度限制必然出现在有正有负的情况下,手推几个简单的例子就能看出来。
那么我们用sum[i]表示前i个的前缀和。那么C[i]<0就表示sum[k+C[i]]-sum[k]<0即sum[k+C[i]]<sum[k]。同理C[i]>0我们也可以得到不等关系。那么就可以建图了,对于不等式sum[a]<sum[b],就建一点从a到b的又向边。如果这个图中出现了环(大于一个点的强联通分量),就意味着无解。
我们二分一个答案n,就意味着有从sum[0],sum[1],sum[2],...sum[n]这n+1个点,建好图后跑一次tarjan算法即可。
#include <bits/stdc++.h>
#define maxn 2009
#define maxm 4000009
using namespace std;
struct Edge
{
int v,next;
}edge[maxm];
int head[maxn],tot,n,m;
int dfn[maxn],low[maxn],stk[maxn],in[maxn],cnt[maxn],top,dfs_time,bcnt;
int a[maxn],num;
void tarjan(int u)
{
low[u]=dfn[u]=++dfs_time;
in[u]=1;
stk[++top]=u;
for(int e=head[u];e!=-1;e=edge[e].next)
{
int v=edge[e].v;
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(in[v])
{
low[u]=min(low[u],dfn[v]);
}
}
if(low[u]==dfn[u])
{
int x;
bcnt++;
cnt[bcnt]=0;
do
{
x=stk[top--];
in[x]=0;
cnt[bcnt]++;
}while(x!=u);
}
}
void addedge(int u,int v)
{
edge[tot].v=v;
edge[tot].next=head[u];
head[u]=tot++;
}
bool check(int mid)
{
n=mid;
memset(head,-1,sizeof(head));tot=0;
for(int j=0;j<num;j++)
{
int len=abs(a[j]);
for(int i=0;i+len<n;i++)
{
if(a[j]<0)
addedge(i,i+len);
else
addedge(i+len,i);
}
}
memset(dfn,0,sizeof(dfn));
dfs_time=bcnt=0;
for(int i=0;i<n;i++)
{
if(!dfn[i])
tarjan(i);
}
for(int i=1;i<=bcnt;i++)
{
if(cnt[i]>1)
return 0;
}
return 1;
}
class LongestSequence
{
public:int maxLength(vector <int> C)
{
num=C.size();
for(int i=0;i<num;i++)
a[i]=C[i];
if(check(2002))
return -1;
int L=0,R=2002;
while(L<R)
{
int M=(L+R+1)>>1;
if(check(M))
L=M;
else
R=M-1;
}
return L-1;
}
};