2017 ECfinal D.Mr. Panda and Geometric Sequence(数学 思维 枚举)

D.Mr. Panda and Geometric Sequence

题意:给你一个l,r,问构造一个满足等比数列拼接而成的数在[l,r]区间内有多少个
其中等比数列的公比可以为分数

分析:对于每个数列的公比 设为p/q 且满足gcd(p,q)=1恒成立 因为数列最少要为3项 所以枚举第一项时 设x=ipp y=iqp z=iqq 这样保证前三个必为整数 且 y<=1e5 对于之后枚举的数要求
z*q%p == 0 最后存入答案 去重 二分查找

//https://codeforces.com/gym/101775/problem/D
#include
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
int check(ll x){//拆分
	if (x == 0) return 1;
	int res = 0;
	while (x){
		res++;
		x /= 10;
	}
	return res;
}
vector<ll>v;//存符合条件的数
ll f[17];
ll gcd(ll x, ll y){
	return y == 0 ? x : gcd(y, x%y);
}
int cnt;//记录去重后的长度
void init(){//预处理
	f[0] = 1;
	for (int i = 1; i <= 16; i++)
		f[i] = f[i - 1] * 10;
	for (ll p = 1; p <= 1e5; p++){//枚举分母
		for (ll q = p+1; q <= 1e5/p; q++)//枚举分子
		{
			if (gcd(p, q) != 1) continue;
			for (ll i = 1; i <= 1e5 / p / q; i++){//枚举第一个数
				ll x = i*p*p, y = i*p*q, z = i*q*q;
				int xx = check(x), yy = check(y), zz = check(z);
				if (xx + yy + zz > 15) break;
				//接着枚举后面的位数
				int len = xx + yy + zz;
				ll sum = x*f[yy + zz] + y*f[zz] + z;
				while (1){
					v.push_back(sum);
					if (z*q%p != 0) break;
					ll a = z*q / p;
					int aa = check(a);
					if (len + aa > 15) break;
					len += aa;
					sum = sum*f[aa] + a;
					z = a;
				}
			}
		}
	}
	sort(v.begin(), v.end());
	cnt=unique(v.begin(), v.end())-v.begin();
}
int main(){
	init();
// 	for (auto it : v)
// 		cout << it << endl;
// 	cout << cnt << endl;//1117个
	int T;
	cin >> T;
	int Cas = 0;
	while (T--){
		ll l, r;
		scanf("%lld%lld", &l, &r);
		int x = lower_bound(v.begin(), v.begin() + cnt, l) - v.begin();
		int y = upper_bound(v.begin(), v.begin() + cnt, r) - v.begin()-1;
		//cout << x << " " << y << endl;
		printf("Case #%d: %d\n", ++Cas, y - x + 1);
	}
	return 0;
}

你可能感兴趣的:(Codeforces,数论)