2016"百度之星"

  分析:按照题目所给的意思每次处理得到的新的字符串都是具有高度对称性的,举个例子,如题目所给的第三个字符串,最中间的是B然后两边分散开去,一边是B的话另外一边关于这个中心对称的那个位置一定是D,反过来同理。那么从任意一点,只要找出他的对称中心,从对称中心的另一边到这一点他们之间的所有字符中,去除掉对称中心是B以外,其他的那些字母中,B和D的个数一定是相等的(从题目中所给的变换方法可知)。那么这题就很简单了。就是关于这个对称中心找出这点到其对称点的长度len,B的个数就是len/2+1,因为len显然是奇数,所以(len+1)/2也无妨。

  我们定义dfs(x)表示从第一个到第x个有多少个B,于是从l到r的答案就是dfs(r)-dfs(l-1)。那么现在不妨拿这个长度为7的BBDBBDD来说明dfs这个方法,如果x是7,它是处于这个对称区间的边缘的,直接给出(7+1)/2=4就好了,但是如果是6呢?很显然的要求1到6的B的个数的话,关于第四个对称,字符串被分割成了B BDBBD D这样子,单单用(5+1)/2只能得到3,原因很简单,第一个字母没被考虑,那么只要在对剩下的部分递归进行同样的操作即可。

  关于是不是这个位置处于边界,我们可以简单地预处理出每个字符串的长度:1,3,7,15... ...这样子的话就可以很容易的知道x是属于哪个对称区间里面了,具体见代码:

 1 #include <stdio.h>
 2 #include <algorithm>
 3 #include <string.h>
 4 #include <vector>
 5 using namespace std;
 6 typedef long long ll;
 7 
 8 vector<ll> V;
 9 void init()
10 {
11     ll x=1;
12     while(x<=(ll)1e18)
13     {
14         V.push_back(x);
15         x=2*x+1;
16     }
17 }
18 
19 ll dfs(ll x)
20 {
21     if(x==0) return 0;
22     int y=lower_bound(V.begin(),V.end(),x)-V.begin();//找出x被包含在那个对称区间里面
23     if(V[y]==x) return (x+1)/2;     //如果刚好处于对称区间的边缘,直接返回,因为前面没有没被处理完的字母了
24     ll t = V[y-1]+1;                //不然的话,很显然前面那个字符串的最后一个位置加1就是x处于的对称区间的对称中心
25     return x-t+1+dfs(x-2*(x-t)-1);   //分治剩余部分
26 }
27 
28 int main()
29 {
30     init();
31     int T;
32     scanf("%d",&T);
33     while(T--)
34     {
35         ll l,r;
36         scanf("%I64d%I64d",&l,&r);
37         ll ans = dfs(r)-dfs(l-1);
38         printf("%I64d
",ans);
39     }
40     return 0;
41 }
原文地址:https://www.cnblogs.com/zzyDS/p/5516600.html