DEF Java

D 切割 01 串 2.0

区间动态规划,前缀和记录分别01的个数,从小区间开始更新,每个区间的方案数都是由旗下的分割更新而来的,时间复杂度O(n^3)

import java.util.*;
public class Main{
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt(),l=sc.nextInt(),r=sc.nextInt(),pre[][]=new int[n+1][2],ans[][]=new int[n][n];
        String s=sc.next();
        for(int i=1;i<=n;i++){
            pre[i]=pre[i-1].clone();
            pre[i][s.charAt(i-1)-'0']++;
        }
        for(int d=1;d<n;d++){
            for(int i=0;i<n-d;i++){
                for(int j=i;j<i+d;j++){
                    int c=Math.abs((pre[j+1][0]-pre[i][0])-(pre[i+d+1][1]-pre[j+1][1]));
                    if(c>=l&&c<=r){
                        ans[i][i+d]=Math.max(ans[i][i+d],1+ans[i][j]+ans[j+1][i+d]);
                    }
                }
            }
        }
        System.out.println(ans[0][n-1]);
    }
}

E and xor or

考虑每个二进制位,只有在区间内,该位既有1又有0的时候,这个以为计算之后才会是1,因此在固定右端点,左端点越靠左,计算得到的数越大,采用二分寻找两次端点,中间的部分符合要求,时间复杂度O(nlog(nC)),其中C==63

import java.util.*;
public class Main{
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt(),k1=sc.nextInt(),k2=sc.nextInt(),pre[][]=new int[n+1][63];
        for(int i=1;i<=n;i++){
            long a=sc.nextLong();
            pre[i]=pre[i-1].clone();
            for(int j=0;j<63;j++){
                pre[i][j]+=(int)(a>>j&1);
            }
        }
        long ans=0;
        for(int i=1;i<=n;i++){
            ans+=find(pre,i,k1)-find(pre,i,k2);
        }
        System.out.println(ans);
    }
    static int find(int pre[][],int idx,int k){
        int l=0,r=idx-1;
        while(l<r){
            int mid=(l+r)>>1;
            if(check(pre,mid,idx,k)){
                r=mid;
            }
            else{
                l=mid+1;
            }
            if(l==r-1){
                if(check(pre,l,idx,k)){
                    r=l;
                }
                break;
            }
        }
        return r;
    }
    static boolean check(int pre[][],int l,int r,int k){
        for(int i=62;i>=k;i--){
            if(pre[r][i]!=pre[l][i]&&pre[r][i]-pre[l][i]!=r-l){
                return false;
            }
        }
        return true;
    }
}

F 绝妙的手法

据说官解也不对,让子弹飞一会儿。。。