qzezoj 1569 寻找连续最长数列
题面传送门
这道题一眼就是排序,但\(O(nlog^2n)\)的复杂度过不去(\(PS\):但有人卡过去了),所以我们要换一个思路
事实上这道题我有一个奇葩想法,居然拓展出了图论模型......
好吧,既然这样,我就来讲讲。
题目中要我们求最长连续数列,那么这个最长连续数列一定是一条链的关系:\(k\)扣着\(k-1\),\(k-1\)扣着\(k-2\)......
则这样我们可以建边,将\(a_i\)向\(a_i-1\)建边,但要确保有\(1\leq j \leq n\)的\(a_j=a_i-1\)。为了满足这个关系,我们可以用\(hash\)来处理
我们建完了图,然后就变成了求解\(DAG\)图上最长链的问题了,求解\(DAG\)图上最长链一般用\(toposort\),但这道题不用,为什么呢
因为要用\(toposort\)求解图上最长链的图不是一棵树,可能一个点有两个入度两个出度,但这道题这样建图保证一个点最多只有一个入度,一个出度,所以可以找到入度为\(0\)的点,用循环一遍解决。
代码实现:
#include<cstdio>
#include<cstring>
#define max(a,b) ((a)>(b)?(a):(b))
#include<cmath>
#define abs(x) ((x)<0?-(x):(x))
#define mod 10000007
using namespace std;
int n,a[1000039],s1[1000039],s2[1000039],ans,tot=1,pus,f[1000039],z[1000039],h[10000039],head;
inline void add(register int x) {
register int now=abs(x)%mod;
//printf("%d\n",now);
register int ss=h[now];
while(ss!=-1) {
if(f[ss]==x) break;
ss=z[ss];
}
if(ss==-1) {
f[++head]=x;
z[head]=h[now];
h[now]=head;
}
}
inline int _hash(register int x) {
register int now=abs(x)%mod;
register int ss=h[now];
while(ss!=-1) {
if(f[ss]==x) break;
ss=z[ss];
}
if(ss==-1) return 0;
else return 1;
}
inline void read(register int &x) {
char s=getchar();int f=1;x=0;
while(s<'0'||s>'9') {if(s=='-') f=-1;s=getchar();};
while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+(s^48),s=getchar();
x*=f;
}
int main() {
// freopen("1.in","r",stdin);
memset(h,-1,sizeof(h));
register int i;
scanf("%d",&n);
for(i=1; i<=n; i++) read(a[i]),add(a[i]);
for(i=1; i<=n; i++) {
s1[i]=_hash(a[i]-1);
s2[i]=_hash(a[i]+1);
}
for(i=1; i<=n; i++) {
if(s1[i]&&!s2[i]) {
tot=0;
//printf("%d\n",i);
pus=a[i];
while(_hash(pus-1)){
tot++;pus--;
}
ans=max(ans,tot);
}
}
printf("%d\n",ans+1);
}
目前\(rank1\),不服来战!!