[ABC322G] Two Kinds of Base

第一次赛后马上AK ABC,好激动,感觉是这场太水了,一看评分,G有2800?!

感觉这个 Trick 挺有用的:某些变量真正能取到的值其实远远没有给的范围那么大,除了某些特殊情况,而这些特殊情况可以用特殊的方式统计答案。

题意

对于一个非负整数序列 \(S=(S_1,S_2,\dots,S_k)\) 和一个整数 \(a\),定义函数 \(f(S,a)\) 如下:

\[f(S,a) = \sum_{i=1}^{k} S_i \times a^{k - i} \]

给定正整数 \(N\)\(X\)。求满足以下所有条件的非负整数序列 \(S=(S_1,S_2,\dots,S_k)\) 和正整数 \(a\)\(b\) 的三元组 \((S,a,b)\) 的数量模 \(998244353\)

  • \(k \ge 1\)
  • \(a,b \le N\)
  • \(S_1 \neq 0\)
  • \(S_i < \min(10,a,b)(1 \le i \le k)\)
  • \(f(S,a) - f(S,b) = X\)

思路

首先,可以把数列 \(S\) 分别看做是 \(k\)\(a\) 进制数和 \(k\)\(b\) 进制数每一位上的值,记这两个数分别记作 \(A\)\(B\)。题目中的最后一个限制就等价于 \(A-B=X\),其中 \(X\) 是十进制意义下的。

显然 \(f(S,a) - f(S,b) = \sum_{i=1}^{k} S_i \times (a^{k - i}-b^{k - i})\),由于 \(X\) 为正整数,故 \(a > b\)

所以上式的这一部分 \(a^{k - i}-b^{k - i}\)\(i\) 增大单调递减,当 \(i=k\) 时,\(a^{0}-b^{0} = 0\),即 \(S_k\) 的取值不会对 \(A-B\) 的值产生影响。

考虑最朴素的做法,枚举 \(k,a,b\),并构造一种合理的 \(S\) 使得满足上述限制。可以证明,如果存在这样的一个 \(S\),那么 \((S_1,S_2,\dots,S_{k-1})\) 是唯一的。

证明:假设从 \(i=1\) 开始依次填 \(S_i\),设 \(X'\) 表示 \(X\) 减去 \(S_1\)\(S_{i-1}\) 的总贡献后的值, \(S_{i+1}\)\(S_k\) 能产生的最大贡献为 \(C\)\(S_i=1\) 时仅 \(S_i\) 产生的贡献为 \(D\)。能得到:\(D=a^{k-i}-b^{k-i}=(a-1)\times\sum_{j=i+1}^{k} a^{k-j}-(b-1)\times\sum_{j=i+1}^{k} b^{k-j} > (b-1)\times(\sum_{j=i+1}^{k} a^{k-j}-\times\sum_{j=i+1}^{k} b^{k-j})\)。所以,当 \(X'>C\) 时,只有 $S_i= \left \lfloor \frac{X'}{a^{k-i} - b^{k-i}}\right \rfloor $ 时才有可能满足条件。而当 \(X'\le C\) 时,\(S_i\) 只能等于 \(0\)。如此贪心地往下填 \(S\) 的每一位,一直到 \(S_{k-1}\),能确定一组唯一的 \((S_1,S_2,\dots,S_{k-1})\)

这样在固定 \(k,a,b\) 的情况下可以 \(O(k)\) 地统计答案,\(k\) 的范围是 \(O(\log X)\) 级别,但 \(a,b\) 的范围却是与 \(n\) 同阶的。

其实有效的 \(a,b\) 远没有这么多。

由于 \(S_1 \neq 0\),这等价于 \(a^{k-1}-b^{k-1} \le X\),可以发现,当 \(k \ge 3\) 时,满足这个条件的二元组 \((a,b)\) 是很少的(当 \(N=10^9,X=2\times 10^5\) 时,只有 \(620787\) 组),每一次可以用 \(O(\log X)\) 的时间统计答案。

而当 \(k = 2\) 时,\(X = (a-b)\times S_1\),用 \(O(\sqrt x)\) 的时间统计答案即可。

Code

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define l(x) x<<1
#define r(x) x<<1|1
#define mpr make_pair
//mt19937_64 ra(time(0) ^ (*new char));
const ll SIZE = 200005;
const ll mod = 998244353;
ll n, X, ans;

inline ll rd(){
	ll f = 1, x = 0;
	char ch = getchar();
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9'){
		x = (x << 1) + (x << 3) + (ch ^ 48);
		ch = getchar();
	}
	return f*x;
}

ll power(ll x, ll y){
	ll jl = 1;
	while(y){
		if(y & 1) jl = (jl * x);
		x = (x * x);
		y >>= 1;
	}
	return jl;
}

int main(){
	n = rd(), X = rd(); ll cnt = 0;
	for(ll i = 1; i*i <= X; i++){
		if(X%i == 0){
			if(i < 10){
				for(ll a = i+1+(X/i); a <= n; a++){
					ll b = a-(X/i);
					if(b >= 10) break;
					ans = (ans + min(10ll, b)) % mod;
				}
				if(n-(X/i) >= 10){
					ans = (ans + (10 * (n-(X/i)-10+1)) % mod) % mod;
				}
			}
			if(i != (X/i) && (X/i) < 10){
				for(ll a = (X/i)+1+i; a <= n; a++){
					ll b = a-i;
					if(b >= 10) break;
					ans = (ans + min(10ll, b)) % mod;
				}
				if(n-i >= 10){
					ans = (ans + (10 * (n-i-10+1)) % mod) % mod;
				}
			}
		}
	}
	for(ll k = 3; k <= 20; k++){
		for(ll a = 1; a <= n; a++){
			if(power(a, k-1)-power(a-1, k-1) > X) break;
			for(ll b = a-1; b >= 1; b--){
				if(power(a, k-1)-power(b, k-1) > X) break;
				ll jl = X; bool flag = 1;
				for(ll i = 1; i < k; i++){
					if(jl / (power(a, k-i)-power(b, k-i)) >= min(10ll, min(a, b))) flag = 0;
					jl = (jl % (power(a, k-i)-power(b, k-i)));
				}
				if(jl == 0 && flag){
					ans = (ans + min(10ll, min(a, b))) % mod;
				}
			}
		}
	}
	printf("%lld", ans);
	return 0;
}
posted @ 2023-10-06 19:14  Semorius  阅读(66)  评论(0)    收藏  举报