【数形结合】Erratic Expansion

[UVa12627]Erratic Expansion

算法入门经典第8章8-12(P245)

 

题目大意:起初有一个红球,每一次红球会分成三红一蓝,蓝球会分成四蓝(如图顺序),问K时的时候A~B行中有几个红色。

试题分析:很容易注意到,按照此种规律,矩形的左上角、右上角、左下角总是与上一个时刻的图形一样,这是我们分治的基础。

     那么,既然得到了上面的,利用前缀和的思想,设f(k,i)表示k时刻从1到i行的红色数量,则答案为f(k,B)-f(k,A-1)

     我们知道,第i个时刻的正方形边长为2^k,那么当i小于等于2^k时,就是上一个同样行的红色的数量*2(因为拓展了)

     那么如果i大于2^k时,我们要怎么办呢?

     首先,最显而易见的是左上角与右上角都是上一个时刻的图形,那么k时刻的红色总和为3^k,所以左上角右上角加起来就是2*(3^(k-1))。

     那么剩下的那些也就是同上面的一样计算,也就是f(k-1,i-2^(k-1))了。

 

代码:

#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;

#define LL long long

inline LL read(){
	LL x=0,f=1;char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
	for(;isdigit(c);c=getchar()) x=x*10+c-'0';
	return x*f;
}
const LL INF=9999999;
const LL MAXN=100000;
LL T; LL C[MAXN+1];
LL Case;
LL K,N,M; 
LL F(LL k,LL p){
	if(p==0) return 0;
	if(k==0) return 1;
	if(p>=(1<<(k-1))) return F(k-1,p-(1<<(k-1)))+2*C[k-1];
	else return 2*F(k-1,p);
}

int main(){
	T=read();C[0]=1;
	for(LL i=1;i<=31;i++) C[i]=C[i-1]*3;
	while(T--){
		++Case;
		K=read(),N=read(),M=read();
		printf("Case %d: %lld\n",Case,F(K,M)-F(K,N-1));
	}
	return 0;
}
posted @ 2017-09-15 22:23  wxjor  阅读(260)  评论(0编辑  收藏  举报