Fence(codeforces 232D)

题意:

对于给定的a[1..n],定义区间[s,t]和[x,y]"匹配"当且仅当下列条件同时满足:
1. t-s=y-x,即长度相同。
3. t<x或s>y,即两区间没有交。
2. 对任0<=i<=t-s,有a[s]+a[x]=a[s+i]+a[x+i]。
现给出a[1..n]和Q个询问(x,y),求与[x,y]匹配的区间的个数。

/*
    写了n个小时,还没有调出来,Orz...
    代码量倒是不大,但是细节巨多,已经弃疗了。。。

    先差分一下, 然后题目就变成了,也就是这段区间取相反数之后可以与原区间匹配。
    设当前询问为(x,y),把整个串取相反数,再复制到后面,用后缀数组向上向下二分出可行区间。
    然后要求不可重叠,就是求rank在(l,r)中有多少串的位置在一个区间内,用主席树搞一搞。
*/
#include<cstdio>
#include<iostream>
#include<algorithm>
#define N 200010
using namespace std;
int id[N],a[N],b[N],s[N],t1[N],t2[N],c[N],sa[N],rank[N],height[N],n;
int lg2[N],st[N][20],sum[N*11],son[N*11][2],root[N],cnt;
struct node{
    int x,num;
    bool operator<(const node&s1)const{
        if(x==s1.x) return num<s1.num;
        return x<s1.x;
    }
}r[N];
bool cmp(int *y,int a,int b,int k){
    int a1=y[a],b1=y[b];
    int a2=a+k<=n?y[a+k]:-1;
    int b2=b+k<=n?y[b+k]:-1;
    return a1==b1&&a2==b2;
}
void DA(){
    int *x=t1,*y=t2,m=1;
    for(int i=1;i<=n;i++) r[i]=(node){s[i],i};
    sort(r+1,r+n+1);
    for(int i=1;i<=n;i++) sa[i]=r[i].num;
    x[sa[1]]=1;
    for(int i=2;i<=n;i++) x[sa[i]]=r[i].x==r[i-1].x?m:++m;
    for(int k=1,p=0;k<=n;k*=2,m=p,p=0){
        for(int i=n-k+1;i<=n;i++) y[++p]=i;
        for(int i=1;i<=n;i++) if(sa[i]>k) y[++p]=sa[i]-k;
        for(int i=1;i<=m;i++) c[i]=0;
        for(int i=1;i<=n;i++) c[x[y[i]]]++;
        for(int i=2;i<=m;i++) c[i]+=c[i-1];
        for(int i=n;i;i--) sa[c[x[y[i]]]--]=y[i];
        swap(x,y);p=1;x[sa[1]]=1;
        for(int i=2;i<=n;i++)
            if(cmp(y,sa[i-1],sa[i],k)) x[sa[i]]=p;
            else x[sa[i]]=++p;
        if(p>=n) break;
    }
}
void geth(){
    for(int i=1;i<=n;i++) rank[sa[i]]=i;
    for(int i=1,j=0;i<=n;i++){
        if(rank[i]==1) continue;
        while(s[i+j]==s[sa[rank[i]-1]+j]) j++;
        height[rank[i]]=j;
        if(j) j--;
    }
    for(int i=2;i<=n;i++) lg2[i]=lg2[i>>1]+1;
    for(int i=1;i<=n;i++) st[i][0]=height[i];
    for(int j=1;(1<<j)<=n;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
            st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]);
}
void insert(int &k,int last,int l,int r,int pos){
    k=++cnt;
    son[k][0]=son[last][0];
    son[k][1]=son[last][1];
    sum[k]=sum[last]+1;
    if(l==r) return;
    int mid=l+r>>1;
    if(pos<=mid) insert(son[k][0],son[last][0],l,mid,pos);
    else insert(son[k][1],son[last][1],mid+1,r,pos);
}
int query(int k,int l,int r,int x,int y){
    if(l>=x&&r<=y) return sum[k];
    int mid=l+r>>1,tot=0;
    if(x<=mid) tot+=query(son[k][0],l,mid,x,y);
    if(y>mid) tot+=query(son[k][1],mid+1,r,x,y);
    return tot;
}
int querymn(int x,int y){
    int k=lg2[y-x+1];
    return min(st[x][k],st[y-(1<<k)+1][k]);
}
int work(int x,int y){
    int pos=rank[x],l=0,r=pos,tmp1=pos,tmp2=pos;
    while(l<r-1){
        int mid=l+r>>1;
        if(querymn(mid+1,pos)>=y-x+1) r=mid,tmp1=mid;
        else l=mid;
    }
    l=pos,r=n+1;
    while(l<r-1){
        int mid=l+r>>1;
        if(querymn(pos+1,mid)>=y-x+1) l=mid,tmp2=mid;
        else r=mid;
    }
    int ans1=query(root[tmp2],1,n+1,x+n/2+1,y+n/2+2)-query(root[tmp1-1],1,n+1,x+n/2+1,y+n/2+2);
    int ans2=query(root[tmp2],1,n,1,n/2)-query(root[tmp1-1],1,n,1,n/2);
    return tmp2-tmp1+1-ans1-ans2;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<n;i++) s[i]=a[i+1]-a[i],s[i+n]=-s[i];s[n]=-1e9;
    n=n*2-1;DA();geth();
    for(int i=1;i<=n;i++)
        insert(root[i],root[i-1],1,n,sa[i]);
    int Q;scanf("%d",&Q);
    while(Q--){
        int x,y;scanf("%d%d",&x,&y);
        if(x==y){
            printf("%d\n",n/2);
            continue;
        }
        printf("%d\n",work(x,y-1));
    }
    return 0;
}
时间: 2024-10-14 08:03:23

Fence(codeforces 232D)的相关文章

SPOJ:House Fence(分治&amp;DP)

"Holiday is coming, holiday is coming, hurray hurray!" shouts Joke in the last day of his college. On this holiday, Joke plans to go to his grandmother's house located in Schematics village. Joke's grandmother's house is more than a hundred year

[题解]Yet Another Subarray Problem-DP 、思维(codeforces 1197D)

题目链接:https://codeforces.com/problemset/problem/1197/D 题意: 给你一个序列,求一个子序列 a[l]~a[r] 使得该子序列的 sum(l,r)-k*(r-l+1)/m(向上取整)的值是在所有子序列中最大的,并输出最大值 思路: 法一:动态规划 dp[i][j] 表示序列到i截止,这一轮已经进行了j次取数(j = (len+m-1)%m) 那么dp[i][j]维护的就是起点为 s = i-j+1-m*t (t>=0)这个集合的最优,这样所有的

AC自动机+dp(CodeForces - 86C )

"Multidimensional spaces are completely out of style these days, unlike genetics problems" — thought physicist Woll and changed his subject of study to bioinformatics. Analysing results of sequencing he faced the following problem concerning DNA

Palindrome Degree(CodeForces 7D)—— hash求回文

学了kmp之后又学了hash来搞字符串.这东西很巧妙,且听娓娓道来. 这题的题意是:一个字符串如果是回文的,那么k值加1,如果前一半的串也是回文,k值再加1,以此类推,算出其k值.打个比方abaaba,k值为3,abaxxaba,k值为1.现在,给出一个串,让你求这个串的所有前缀(包括本身)的k值的和. 如果考虑马拉车,那么先预处理出每个地方的最长回文长度,然后不断的截断,如果子串的回文长度大于其回文长度,那么k值加1,这样即可.但是马拉车写起来比较繁琐,没有模板我也没法手写. 这里提供hash

A - Playing with Paper (CodeForces - 527A)

- 题目大意 给定的矩形,每次裁剪最大的正方形,直到最后剩下正方形,总共有多少个正方形. - 解题思路 显然,每次裁剪后,原来的宽和(长-宽)变成了现在的长和宽,直到长等于宽. - 代码 #include<iostream> using namespace std; long long num(long long a, long long b) { if (b == 1) return a; if (a % b == 0) return a / b; return num(b, a % b)

587. Erect the Fence(凸包算法)

问题 给定一群树的坐标点,画个围栏把所有树围起来(凸包). 至少有一棵树,输入和输出没有顺序. Input: [[1,1],[2,2],[2,0],[2,4],[3,3],[4,2]] Output: [[1,1],[2,0],[4,2],[3,3],[2,4]] 思路和代码 1. 暴力法(超时) 对于任意两点连成的一条直线,如果其它所有点都在这条直线的一侧,则这两个点为解集中的两个点. 怎么判断点在直线的同一侧呢? 假设确定直线的两点为p1(x1, y1)和p2(x2, y2),方向从p1到p

Codeforces 448C Painting Fence(分治法)

题目链接:http://codeforces.com/contest/448/problem/C 题目大意:n个1* a [ i ] 的木板,把他们立起来,变成每个木板宽为1长为 a [ i ] 的栅栏,现在要给栅栏刷漆,刷子宽1,刷子可以刷任意长,每次只能横着刷或者竖着刷,问最少需要刷几次?解题思路:参考了这里(https://blog.csdn.net/qq_24451605/article/details/48492573)首先我们能够想到,如果横着刷,为了得到最优解,当前刷的位置的下面也

Codeforces Round #256 (Div. 2) C. Painting Fence(分治贪心)

题目链接:http://codeforces.com/problemset/problem/448/C ---------------------------------------------------------------------------------------------------------------------------------------------------------- 欢迎光临天资小屋:http://user.qzone.qq.com/593830943

「6月雅礼集训 2017 Day10」perm(CodeForces 698F)

[题目大意] 给出一个$n$个数的序列$\{a_n\}$,其中有些地方的数为0,要求你把这个序列填成一个1到$n$的排列,使得: $(a_i, a_j) = 1$,当且仅当$(i, j) = 1$.多组数据. $n \leq 3\times 10^5, T\leq 10$ CodeForces:无多组数据,$n \leq 10^6$ [题解] 这题有点神奇啊.. 首先考虑序列全是0要怎么做. 考虑到如果两个数的位置含有的因数种类完全一样,那么它们是可以互换的.(这个挺显然的) 观察如果两个质数的