码迷,mamicode.com
首页 > 其他好文 > 详细

【codeforces】ZeptoLab Code Rush 2015 E 跳跃表?

时间:2015-04-05 15:49:42      阅读:121      评论:0      收藏:0      [点我收藏+]

标签:

题意就是给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)的。

 

 

#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 \n",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 \n",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\n",ret);
}
return 0;
}

【codeforces】ZeptoLab Code Rush 2015 E 跳跃表?

标签:

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!