DEF Java
区间动态规划,前缀和记录分别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]);
}
}
考虑每个二进制位,只有在区间内,该位既有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;
}
}
据说官解也不对,让子弹飞一会儿。。。