题解 [CF582D] Number of Binominal Coefficients
一眼 Lucas 定理,冷静发现 Lucas 定理仅适用于模数是质数的情况
那么考虑 Kummer 定理
- Kummer 定理:
\(\binom{n+m}{n}\) 中(注意不是 \(\binom{n}{m}\) 中)含有 \(p\) 的次数是 \(n+m\) 在 \(p\) 进制下的进位次数
证明:
含有 \(p\) 的次数是这样一个东西:\[\begin{aligned} cnt&=\sum\limits_{i=1}^{+\infty}\lfloor\frac{n+m}{p^i}\rfloor-\sum\limits_{i=1}^{+\infty}\lfloor\frac{n}{p^i}\rfloor-\sum\limits_{i=1}^{+\infty}\lfloor\frac{m}{p^i}\rfloor\\ &=\sum\limits_{i=1}^{+\infty}\lfloor\frac{n+m}{p^i}\rfloor-\lfloor\frac{n}{p^i}\rfloor-\lfloor\frac{m}{p^i}\rfloor\\ \end{aligned} \]注意 \(p\) 进制下这个除法等价于右移
而 \(\forall i,\lfloor\frac{n+m}{p^i}\rfloor-\lfloor\frac{n}{p^i}\rfloor-\lfloor\frac{m}{p^i}\rfloor=1\) 的充要条件是 \(n, m\) 右移后做加法时产生了进位,于是得证
回到本题
那么容易想到数位 DP
我一开始莫名其妙假在了上面“注意不是”的那个地方
令 \(f_{i, j, 0/1, 0/1}\) 为高到低第 \(i\) 位,产生了 \(j\) 次进位,当前位是否产生进位,\(n+m\) 是否卡上界的合法方案数
转移大力分类讨论,需要实现一个 \(\operatorname{calc}(l, r)\) 为 \(n, m\in[0, p-1], n+m\in[l, r]\) 的方案数
这个东西我只会大力分类讨论值域段
然后得到了某篇题解的一个启发,可以这样推式子处理:
\[\begin{aligned}
\operatorname{calc}(l, r)&=\sum\limits_{k=l}^r\sum\limits_{i=0}^{p-1}\sum\limits_{j=0}^{p-1}[i+j=k]\\
&=\sum\limits_{k=l}^r\sum\limits_{i=0}^{p-1}[k-i\in[0, p-1]]\\
&=\sum\limits_{k=l}^r \max(\min(k, p-1)-max(k-(p-1), 0), 0)\\
&=\sum\limits_{k=l}^r \min(k, p-1)-max(k-(p-1), 0)
\end{aligned}\]
于是只需要分两段简单讨论即可
点击查看代码
#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;
}
浙公网安备 33010602011771号