题解 [CF582D] Number of Binominal Coefficients
一眼 Lucas 定理,冷静发现 Lucas 定理仅适用于模数是质数的情况
那么考虑 Kummer 定理
- Kummer 定理:
中(注意不是 中)含有 的次数是 在 进制下的进位次数
证明:
含有 的次数是这样一个东西:注意 进制下这个除法等价于右移
而 的充要条件是 右移后做加法时产生了进位,于是得证
回到本题
那么容易想到数位 DP
我一开始莫名其妙假在了上面“注意不是”的那个地方
令 为高到低第 位,产生了 次进位,当前位是否产生进位, 是否卡上界的合法方案数
转移大力分类讨论,需要实现一个 为 的方案数
这个东西我只会大力分类讨论值域段
然后得到了某篇题解的一个启发,可以这样推式子处理:
于是只需要分两段简单讨论即可
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 3510
#define pb push_back
#define ll long long
//#define int long long
int p, a;
char t[N];
vector<int> s;
int f[N][N][2][2];
const ll mod=1e9+7, inv2=(mod+1)>>1;
vector<int> tran(vector<int> s) {
int now=0;
vector<int> tem[2], ans;
for (tem[now]=s; tem[now].size(); now^=1) {
ll rest=0;
bool any=0;
tem[now^1].clear();
for (auto it:tem[now]) {
rest=rest*10+it;
if (rest>=p) tem[now^1].pb(rest/p), rest%=p, any=1;
else if (any) tem[now^1].pb(0);
}
ans.pb(rest);
}
if (!ans.size()) ans.pb(0);
while (ans.size()>1&&!ans.back()) ans.pop_back();
// cout<<"ans: "; for (int i=ans.size()-1; ~i; --i) cout<<ans[i]<<' '; cout<<endl;
return ans;
}
// ll calc(ll l, ll r) {
// l=max(l, 0ll);
// r=min(r, 2ll*(p-1));
// if (l>r) return 0;
// cout<<"calc: "<<l<<' '<<r<<endl;
// ll ans=0;
// for (int i=0; i<p; ++i)
// for (int j=0; j<p; ++j)
// if (l<=i+j && i+j<=r) ++ans;
// cout<<"return: "<<ans<<endl;
// return ans;
// }
inline ll qsum(ll n) {return n*(n+1)%mod*inv2%mod;}
ll calc(ll l, ll r) {
l=max(l, 0ll);
r=min(r, 2ll*(p-1));
if (l>r) return 0;
// cout<<"calc: "<<l<<' '<<r<<endl;
ll ans=0;
if (r>=p-1) {
ll tl=max((ll)p-1, l), tr=r;
ans=(ans+(tr-tl+1)*2*(p-1)-(qsum(tr)-qsum(tl-1)))%mod;
}
if (l<p-1) {
ll tl=l, tr=min((ll)p-2, r);
ans=(ans+qsum(tr)-qsum(tl-1))%mod;
}
ans=(ans+(r-l+1))%mod;
// cout<<"return: "<<ans<<endl;
return ans;
}
ll dfs(int i, int j, bool over, bool lim) {
if (i<0) return !over&&j>=a;
if (~f[i][j][over][lim]) return f[i][j][over][lim];
ll ans=0;
if (over) {
if (lim) {
ans=(ans+calc(p+s[i], p+s[i])*dfs(i-1, j, 0, 1))%mod;
ans=(ans+calc(p, p+s[i]-1)*dfs(i-1, j, 0, 0))%mod;
ans=(ans+calc(p+s[i]-1, p+s[i]-1)*dfs(i-1, j+1, 1, 1))%mod;
ans=(ans+calc(p-1, p+s[i]-2)*dfs(i-1, j+1, 1, 0))%mod;
}
else {
ans=(ans+calc(p, 2*(p-1))*dfs(i-1, j, 0, 0))%mod;
ans=(ans+calc(p-1, 2*(p-1))*dfs(i-1, j+1, 1, 0))%mod;
}
}
else {
if (lim) {
ans=(ans+calc(s[i], s[i])*dfs(i-1, j, 0, 1))%mod;
ans=(ans+calc(0, s[i]-1)*dfs(i-1, j, 0, 0))%mod;
ans=(ans+calc(s[i]-1, s[i]-1)*dfs(i-1, j+1, 1, 1))%mod;
ans=(ans+calc(0, s[i]-2)*dfs(i-1, j+1, 1, 0))%mod;
}
else {
ans=(ans+calc(0, p-1)*dfs(i-1, j, 0, 0))%mod;
ans=(ans+calc(0, p-2)*dfs(i-1, j+1, 1, 0))%mod;
}
}
return f[i][j][over][lim]=ans;
}
signed main()
{
// cout<<double(sizeof(f))/1000/1000<<endl;
scanf("%d%d%s", &p, &a, t);
s.resize(strlen(t));
for (int i=0; i<s.size(); ++i) s[i]=t[i]-'0';
s=tran(s);
// cout<<s.size()<<endl; exit(0);
memset(f, -1, sizeof(f));
printf("%lld\n", dfs(s.size()-1, 0, 0, 1));
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?