E
题目大意
对于给出的一个n,找到一个m,使得n%m == S(m)
,其中m<=n,S表示各位数字之和
遍历1~n显然不现实,那么能不能找m呢?
通过变化等式我们可以发现,n-S(m)
取余m为0,也就是m得倍数,也就是m是其因子
因为位数为12,所以S(m)的取值范围不超过120,通过遍历S(m),判断n-S(m)
是否有因子m满足题意,即n%m == S(m)
即可
要求给出有多少个m,其中找因子可以通过Pollard_Rho的算法和Miller-Rabin算法找到质因数,然后通过深搜组合质因子,求得所有因子
代码如下
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define LL __int128
#include<unordered_set>
#include <random>
static mt19937 myrand(time(0));//随机数
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
const ll prime[] = { 2,3,5,7,11,13,17,19,23,29,31,37 };
ll mul(ll x, ll y, ll mod) //使用__int128(部分编译器无法使用,需尝试),正常效率
{
return (__int128)x * y % mod;//防止溢出
}
ll qpow(ll x, ll y, ll p)//快速位幂,处理大数,防止溢出
{
ll res = 1;
while (y)
{
if (y & 1)res = mul(res, x, p);
x = mul(x, x, p);
y >>= 1;
}
return res;
}
bool MillerRabin(ll n, ll a)//判断质数
{
ll d = n - 1, r = 0;
while (!(d & 1))
d >>= 1, r++;
ll z = qpow(a, d, n);
if (z == 1)return true; // 情况 1
// 情况 2
for (int i = 0; i < r; i++)
{
if (z == n - 1)return true;
z = mul(z, z, n);
}
return false;
}
bool isPrime(ll n)
{
if (n <= 1)return false;
for (int i = 0; i < 11; i++)
{
if (n == prime[i])return true; // 特判 1
if (n % prime[i] == 0)return false; // 特判 2
if (!MillerRabin(n, prime[i]))return false;
}
return true;
}
ll Pollard_Rho(ll n)//分解质因数,倍增优化
{
ll c = myrand();
auto f = [&](ll x) {return (((__int128)x * x + c) % n); };//函数内定义函数,'&'表示全继承
ll x = 0, y = 0, s = 1;
for (int k = 1; k <<= 1; y = x, s = 1)
{
for (int i = 1; i <= k; i++)
{
x = f(x);
s = (__int128)s * abs(x - y) % n;
if (i % 127 == 0)
{
ll d = gcd(s, n);
if (d > 1) return d;
}
}
ll d = gcd(s, n);
if (d > 1) return d;
}
return n;
}
vector<ll> factor;
void get_factor(ll n)
{
if (n == 1)
{
return;
}
if (n == 4)//特判
{
factor.push_back(2);
factor.push_back(2);
return;
}
if (isPrime(n))
{
factor.push_back(n);
return;
}
ll x = n;
while (x == n) x = Pollard_Rho(n);//随机性很强
get_factor(x), get_factor(n / x);
}
long long sum(long long m) {//求和
long long sum = 0;
while (m > 0) {
sum += m % 10;
m /= 10;
}
return sum;
}
ll n = 0;
ll ans = 0;
void dfs(ll s, ll i, ll m = 1) {//深搜
if (i >= factor.size())
{
ans +=( n % m == s && sum(m) == s);
return;
}
ll j = i;
for (; j < factor.size() && factor[i] == factor[j]; j++);//跳过重复的质因子
for (ll k = 0; k <= j - i; k++)//对于该质因子的k次方
{
dfs(s, j, m);
m *= factor[i];
}
}
void solve()
{
cin >> n;
ans = 0;
for (ll i = 1; i < 110 && i<n; i++)
{
if (i >= n) break;
factor.clear();
get_factor(n - i);
sort(factor.begin(), factor.end());
dfs(i, 0);
}
cout << ans << endl;
}
int main() {
int t;
cin >> t;
while (t--)
{
solve();
}
return 0;
}