【codeforces】ZeptoLab Code Rush 2015 E 跳跃表? D kmp还不错的题

http://codeforces.com/contest/526/problem/E

题意就是给n个数,围成一圈,就是1和n是相邻的,然后给一个数b,总和不超过b的一段连续的数可以组成一组,问最少可以将n个数分成几组。

可以将n个数后面再接n个数,就变成n+n个数,然后以每个数为开头的组最远能到哪也是很容易求的,O(n)维护个指针可以处理。把远的位置视为跳一步能到的吧,这样问题就转化为1到n中的第i个数至少到第n+i个数要跳多少次。这个如果是一般图的话,就是类似树上求k步的祖先在哪,可以用倍增法,n*log(n)。但是这题图比较特殊,i<j的话,i跳到的下一点位置不会超过j跳到的下一步位置。做法就是从前往后枚举i至少到达n+i的最少位置,最暴力的一步步跳着找,但是中间求完后要记录,就是类似并查集的优化,实质就是跳过的边不会再跳了,记录了跳到最后的是哪个点以及跳了几步,下次就能一次跳到那个点。总复杂度是O(n)的。

http://codeforces.com/contest/526/problem/D

想起D题也不错,虽然比赛时秒了,但是是基于我对KMP的理解的基础上的- -。i-p[i]为从字符串起始位置到当前i位置的循环节,就是说d=i-p[i],每d个字符为一段循环。现在面试题好多想考察KMP,起始都能用hash之类的做,都不是真正的KMP题。 还有扩展KMP是向后的,这个不熟敲不出来,只会二分hash,多个logn的复杂度。

#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<vector>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
using namespace std;
#define mp(x,y) make_pair(x,y)
typedef pair<int,int> per;
typedef long long ll;
const int MOD = 1000000007;
const int N = 1000005;
int pt[N+N],a[N+N],n,f[N+N],cnt[N+N];
ll d;
void got()
{
int i,j=1;
ll sum=0;
for(i=1;i<=n+n;i++)
{
while(j<=n+n&&sum+a[j]<=d)
{
sum+=a[j];
j++;
}
pt[i]=j;
sum-=a[i];
//printf("i:%d pt:%d ",i,pt[i]);
}
}
int fd(int x,int need)
{
if(x>=need)return x;
if(f[x]==x)
{
f[x]=pt[x];
cnt[x]=1;
}
int y=fd(f[x],need);
cnt[x]+=cnt[f[x]];
f[x]=y;
//printf("x:%d need:%d f:%d cnt:%d ",x,need,f[x],cnt[x]);
return y;
}
int main()
{
int q,i,j;
scanf("%d%d",&n,&q);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
a[i+n]=a[i];
}
while(q--)
{
scanf("%I64d",&d);
got();
int ret=N+N;
for(i=1;i<=n+n;i++)
{
f[i]=i;
cnt[i]=0;
}
for(i=1;i<=n;i++)
{
fd(i,n+i);
if(ret>cnt[i])ret=cnt[i];
}
printf("%d ",ret);
}
return 0;
}

原文地址:https://www.cnblogs.com/seen1020/p/4394145.html