您的位置:首页 > 其它

soj1041. Pushing Boxes

2015-04-15 21:14 585 查看

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<math.h>
#define maxn 210001
using namespace std;
int N,M,K;
int a[maxn],sa[maxn],rank[maxn],height[maxn];
int wb[maxn],wv[maxn],sw[maxn],wa[maxn],b[maxn],wm[maxn],temp[maxn];
int f[maxn];
struct node
{
int ori,v;
}c[maxn];
int cp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *a,int *sa,int n,int m)
{
int i,j,p,*rank=wa,*y=wb,*t;//y为排序的第二关键字
memset(sa,0,sizeof(sa));
memset(wb,0,sizeof(wb));
memset(wa,0,sizeof(wa));
for(i=0;i<m;i++) b[i]=0;
for(i=0;i<n;i++)b[rank[i]=a[i]]++;
for(i=1;i<m;i++)b[i]+=b[i-1];
for(i=n-1;i>=0;i--)sa[--b[rank[i]]]=i;
for(j=1,p=1;p<n;j*=2,m=p)
{
for(p=0,i=n-j;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=j)y[p++]=sa[i]-j;
for(i=0;i<n;i++) temp[i]=rank[y[i]];

for(i=0;i<m;i++) b[i]=0;
for(i=0;i<n;i++) b[temp[i]]++;
for(i=1;i<m;i++) b[i]+=b[i-1];
for(i=n-1;i>=0;i--) sa[--b[temp[i]]]=y[i];

for(t=rank,rank=y,y=t,p=1,rank[sa[0]]=0,i=1;i<n;i++)
{
if(cp(y,sa[i-1],sa[i],j))
rank[sa[i]]=p-1;
else
rank[sa[i]]=p++;
}
}
return;
}
int fc(node e1,node e2)
{
if(e1.v<e2.v)return 1;
else return 0;
}
void calheight(int n)
{
long long i,j,k=0;
memset(rank,0,sizeof(rank));
for(i=1;i<=n;i++)
rank[sa[i]]=i;
for(i=1;i<=n;i++)
{
k--;if(k<0)k=0;
for(j=sa[rank[i]-1];a[i+k]==a[j+k];k++);
height[rank[i]]=k;
}
return;
}

long long work(int t)
{
int sum=0;
long long ans=0;
K=t;
for(long long i=2;i<=2*N;i++)
{
if(height[i]<K )
{
if(sa[i-1]<=N)
f[sa[i-1]]-=sum;

sum=0;
}
else if(sa[i-1]<=N)
{
f[sa[i-1]]-=sum;
sum++;
}
}
if(sa[2*N]<=N)
f[sa[2*N]]-=sum;
return ans;
}
int main()
{
freopen("Sa.in","r",stdin);
freopen("Sa.out","w",stdout);
while(scanf("%d",&N)!=EOF)
{
memset(f,0,sizeof(f));
memset(c,0,sizeof(c));
memset(height,0,sizeof(height));
memset(a,0,sizeof(a));
for(int i=1;i<=N;i++)
scanf("%d",&c[i].v),c[i].ori=i;
sort(c+1,c+1+N,fc);
int c1=-1,c2=0;
for(int i=1;i<=N;i++)
{if(c[i].v!=c1)
{
c1=c[i].v;
a[c[i].ori]=++c2;
}
a[c[i].ori]=c2;
}
for(int i=1;i<=N;i++)
a[i+N]=a[i];
da(a,sa,N*2+1,c2+1);
calheight(2*N);
int t=0;
for(int i=1;i<=2*N;i++)
{
if(sa[i]<=N)
{f[sa[i]]=t*(int(log2(N))+1);
t++;}
}
for(int i=1;i<=N;i=(i<<1))
work(i);
for(int i=1;i<N;i++)
printf("%d ",f[i]);
printf("%d\n",f
);
}
}
1023. Funny Contest

Constraints

Time Limit: 3 secs, Memory Limit: 32 MB

Description

Powerful men often play funny game. Today N powerful men sit in a circle and face inward. They all have a power-value. If two men start a fight, the man with the bigger power-value will win. Otherwise there will be a draw if power-value is the same.X-man invites (k-1) men in a consecutive sequence next to his left then makes a group. We call it X-man's k-group. Two k-group fight with each other.(1) Arrange the men in X-man's k-group by the distance from them to X-man in ascending order. (The distancefrom A-man to B-man is the number from A-man to B-man counterclockwise, including A-man and B-man. For example, the distance from a man to himself is 1, and the distance from a man to his left is 2 ...)(2) The fight between two groups--(x1,x2,...xk) and (y1,y2...yk)---willbe a draw if xi=yi for all i(1<=i<=k). The first group will win if there is an i (1<=i<=k) where xi>yi, and xj=yj for all j (1<=j<i), and vice versa.We consider all the k-group and rank them. The rank of a group is the number of groups it can beat.Now we consider the mark of X-man: the sum of the rank of all his k-groups. (k=1,2,4 ... 2^p, 2^p <=N and 2^(p+1)>N)

Input

The first line of the input is a single positive integer N (N<=100000). The next line contains N numbers, the power-value of the men in the circle, clockwise. Power-value is a positive integer which is smaller than 2^31.Input will be ended by the end of file.

Output

For each test case, output one line containing the marks of the men corresponding to the position in the input. There is a space between two marks. 

Sample Input

3

10 3 1

Sample Output

4 2 0

Hint

In the sample :
1-group
(10)   (3)   (1)
rank     2       1     0

2-group
(10,3)   (3,1)   (1 ,10)
rank     2         1       0
多年恩怨,一朝了断,从去年十月第一次见到这题开始已经过去了接近半年了,第一次从noip吧上的大牛那听说了后缀数组,之后又看了几篇论文后,终于有所感触,在昨日凌晨A了这题
题目大意是一群人围成一个环,每个人有一个战斗力,进行多轮战斗。
第k轮战斗时,第i个人的排名就是i的长度为2^(k-1)的后缀的排名。(如果两个后缀相同,排名是一样的)
对于每个i,求其每一轮排名的总和。
solution:
一开始复制一遍数组,因为是一个环。
先用倍增求一次后缀数组,简单实惠。(如果没学过后缀数组,请先学习《后缀数组——处理字符串的有力工具》)
先计算出没有平局(如果两个人固定长度的后缀相同,其排名有先后)时每个人最后的f[i]。
for(int i=1;i<=2*N;i++){if(sa[i]<=N){f[sa[i]]=t*(int(log2(N))+1);t++;}}
接下来对于每个f[i]我们要减去的就是它会和多少个之前的数产生相同的后缀。
然后求相邻后缀的最长公共前缀height[i].枚举每一轮的后缀长度k(2的指数)对height进行分组,每个组内的height都是大于k的,时时记录组内sa[i-1]<=N即首元素在前一半的后缀的个数sum,并且每次碰到sa[i-1]<=N时,f[sa[i-1]]直接减去sum,因为会和sa[i-1]的后缀产生相同排名的只可能是这些和它在同一组内的后缀。
贴码

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  soj sicily 后缀数组 sa