• BZOJ4993 [Usaco2017 Feb]Why Did the Cow Cross the Road II 动态规划 树状数组


    欢迎访问~原文出处——博客园-zhouzhendong

    去博客园看该题解


    题目传送门 - BZOJ4993


    题意概括

      有上下两行长度为 n 的数字序列 A 和序列 B,都是 1 到 n 的排列,若 abs(A[i]-B[j])<=4,则 A[i]和 B[j]间可以连一条边。现求在边与边不相交的情况下的最大连边数量。


    题解

      我们用dp[i][j]表示枚举到A序列的第i个位置,与B序列的第j个位置匹配,所得到的最大效益,这样显然是要超时的,但是不妨去思考一下。

      dp[i][j]=max(dp[i-1][k](1<=k<=j))

      于是我们又发现两个厉害的东西:

      1. 由于每一个数字连出的边最多只有9种情况( abs(A[i]-B[j])<=4),所以转移的复杂度几乎舍去。

      2. 我们发现其实这个东西可以用线段树来维护最大值(当前树状数组也可以的),那么时间复杂度就降成O(n*9 log n)的了。但是线段树的常数太大,被卡了,所以我们用树状数组就可以了。


    代码

    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    using namespace std;
    void read(int &x){
    	x=0;
    	char ch=getchar();
    	while (!('0'<=ch&&ch<='9'))
    		ch=getchar();
    	while ('0'<=ch&&ch<='9'){
    		x=x*10+ch-48;
    		ch=getchar();
    	}
    }
    const int N=1e5+5;
    int n,a[N],b[N],pos[N],ps[10];
    int c[N];
    int lb(int x){
    	return x&-x;
    }
    void update(int x,int d){
    	for (;x<=n;x+=lb(x))
    		c[x]=max(c[x],d);
    }
    int query(int x){
    	int ans=0;
    	for (;x>0;x-=lb(x))
    		ans=max(ans,c[x]);
    	return ans;
    }
    int main(){
    	read(n);
    	for (int i=1;i<=n;i++)
    		read(a[i]);
    	for (int i=1;i<=n;i++)
    		read(b[i]),pos[b[i]]=i;
    	memset(c,0,sizeof c);
    	for (int i=1;i<=n;i++){
    		int tot=0;
    		for (int j=a[i]-4;j<=a[i]+4;j++)
    			if (1<=j&&j<=n)
    				ps[++tot]=pos[j];
    		sort(ps+1,ps+tot+1);
    		for (int j=tot;j>=1;j--)
    			update(ps[j],query(ps[j]-1)+1);
    	}
    	printf("%d",query(n));
    	return 0;
    }
    

      

  • 相关阅读:
    [USACO15FEB][AC自动机][栈] Censoring G
    [USACO06NOV] Round Numbers S
    Emiya家的饭
    dp
    P2498 [SDOI2012]拯救小云公主
    [HEOI2015]小L的白日梦
    SP8064 AMR10J-Mixing Chemicals
    10.24三题
    P4296 [AHOI2007]密码箱
    CF780F
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ4993.html
Copyright © 2020-2023  润新知