HDU 5694 BD String 二分或递归

题目链接:HDOJ        http://acm.hdu.edu.cn/showproblem.php?pid=5694

                VJ               https://vjudge.net/problem/HDU-5694

方法一 : 分类讨论:

            对于任一length>=1的BD串可以分两类:A类满足中点为B,B类满足中点为D

            由进行两组操作后结果可知:同一个串的子A,B子串在除再进行二分的对称点外的其他部分相同,所以该题可以二分求解。

            二分法代码如下:

            代码使用JAVA,和C++基本没区别就不另给c++版本了

import java.util.Scanner;
public class Main {
	static long a[]=new long[61];
	static long b(long x) {
		long ans=0;
		int t=2;//t=1为B类,t=2为A类,易知开始递归前所有串均为A类
		while(x!=0) {
			for(int i=1;i<=60;i++) {
				if(a[i]==x) return ans+a[i-1]+1;//刚好剩下一个完整的A,或B类串
				else if(a[i]+1==x)return ans+a[i-1]+t;//剩下一个完整的A,或B类串和对称轴
                              else if(a[i]>x) {//取走A串+对称轴部分,递归剩余部分
                                     ans+=a[i-2]+t;
                                        x=x-a[i-1]-1;
                                  /*         改变字符串的A,B性        */
					if(x>a[i-2]) {
						t=1;
					}
					else {
						t=2;
					}
					break;
				}
			}
		}
		return ans;
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner in=new Scanner(System.in);
               /*初始化a数组,a[i]表示S(i)的长度,A类:a[i-1]+1,B类:a[i-1]表示S(i)中B的个数*/
		a[0]=0;
		for(int i=1;i<=60;i++) {
			a[i]=a[i-1]*2+1;
		}
		int t=in.nextInt();
		while(t-->0)System.out.println(b(in.nextLong()-1)*-1+b(in.nextLong()));
	}

}




方法2:递归

思路:可以用一个函数calc(x),表示从第一位到第x位中B字符的个数,则结果为calc(R)-calc(L),怎么样求calc(x)呢?
用一个数组a[1]~a[60](a[60]>10^18&a[59]<10^18)表示s(1)~s(60)的串长,若x==a[i],则sum=a[i]/2+1;若x<a[i]&x>a[i-1],则对应a[i-1]+1的字符一定为B,那么关于a[i-1]+1对称的两部分a[i-1]+2~x与a[i]-R+1~a[i-1]字符串取反后对称,所以这两部分字符转中B的个数和为R-a[i-1]-1,加上中间对称的B,个数为R-a[i-1],总的B字符个数为R-a[i-1]+calc(a[i]-R),然后递归求解calc(a[i]-R);
代码如下:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
long long a[70];
long long calc(long long x)
{
    if(x==0) return 0;
    long long sum=0;
    for(int i=1;i<=60;i++)
    {
        if(a[i]==x)
            return x/2+1;
        if(x<a[i])
        {
            sum+=x-a[i-1];
            sum+=calc(a[i]-x);
            break;
        }
    }
    return sum;
}
int main()
{
    int T;
    long long L,R;
    scanf("%d",&T);
    a[0]=0;
    for(int i=1;i<=60;i++)
    {
        a[i]=a[i-1]*2+1;
    }
    while(T--)
    {
        scanf("%I64d%I64d",&L,&R);
        printf("%I64d\n",calc(R)-calc(L-1));
    }
    return 0;
}

posted @ 2018-02-25 13:08  可爱如我  阅读(190)  评论(0编辑  收藏  举报