[题解]P14094 [ICPC 2023 Seoul R] Special Numbers

P14094 [ICPC 2023 Seoul R] Special Numbers

数位 DP。

考虑使用 \(f[pos][g]\) 记忆化,其中:

  • \(pos\) 表示当前填到第几位。
  • \(g\) 表示填过位置的乘积与 \(k\)\(\gcd\)

根据这个表格我们知道,\(10^{17}\) 内的因数最多的数[1]只有不到 \(65536\) 个因数。所以 \(g\) 的取值不超过 \(65536\) 种,将第二维离散化一下就可以了。

代码中,第二位是用哈希表(gp_hash_table)现用现算的,常数不小,但是目前谷上最优解。

点击查看代码
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#define int long long
using namespace std;
using namespace __gnu_pbds;
const int N=25,P=1e9+7;
int k,len,a[N],f[N][65536],idx;
string l,r;
gp_hash_table<int,int> ma;
inline int gcd(__int128 a,int b){
	int r=a%b;
	while(r) a=b,b=r,r=a%b;
	return b;
}
inline int dfs(int p,__int128 fc,bool zro,bool lim){
	int g=gcd(fc,k),gg;
	if(!p) return g==k;
	if(ma.find(g)==ma.end()) ma[g]=gg=idx++;
	else gg=ma[g];
	if(!zro&&!lim&&(~f[p][gg])) return f[p][gg];
	int rig=lim?a[p]:9,ans=0;
	for(int i=0;i<=rig;i++){
		bool tzro=zro&&!i;
		ans+=dfs(p-1,tzro?1:fc*i,tzro,lim&&i==rig);
	}
	ans%=P;
	if(!zro&&!lim) f[p][gg]=ans;
	return ans;
}
inline int solve(string& s){
	len=s.size();
	for(int i=0;i<len;i++) a[len-i]=s[i]-'0';
	return dfs(len,1,1,1);
}
inline bool check(string& s){
	int f=1;
	for(int i:s) if(!((f*=i-'0')%=k)) return 1;
	return 0;
}
signed main(){
	memset(f,-1,sizeof f);
	cin>>k>>l>>r;
	cout<<(solve(r)-solve(l)+check(l)+P)%P<<"\n";
	//字符串-1不好做,左端点单独处理(其实int128就可以)
	return 0;
}

另一种做法是考虑到 \(k\) 若有某个超过 \(10\) 的质因数,则一定无解。因此只需要用质因子 \(2,3,5,7\) 的指数进行记忆化即可。


  1. 即 Highly Composite Numbers,表格数据来源↩︎

posted @ 2025-11-05 21:38  Sinktank  阅读(11)  评论(0)    收藏  举报
★CLICK FOR MORE INFO★ TOP-BOTTOM-THEME
Enable/Disable Transition
Copyright © 2023 ~ 2025 Sinktank - 1328312655@qq.com
Illustration from 稲葉曇『リレイアウター/Relayouter/中继输出者』,by ぬくぬくにぎりめし.