CF756E Byteland coins 题解
题目描述
\(n\) 种货币,第 \(1\) 种货币面值为 \(1\) ,第 \(k+1\) 种货币的面值是第 \(k\) 种的 \(a_k\) 倍。
保证 \(\forall x\) ,面值为 \(x\) 的货币种类不超过 \(20\) 。
第 \(k\) 种货币有 \(b_k\) 个,求有多少种组成面值 \(m\) 的方案,对 \(10^9+7\) 取模。
两种方案不同,当且仅当至少一种货币出现次数不同。
数据范围
- \(1\le n\le 3\cdot 10^5,0\le m\le 10^{10000}\) 。
- \(1\le a_i\le 10^9,0\le b_i\le 3\cdot 10^5,\sum b_i\le 3\cdot 10^5\) 。
时间限制 \(\texttt{1s}\) ,空间限制 \(\texttt{512MB}\) 。
分析
先考虑 \(a_i\neq 1\) 的情况,容易想到数位 \(\texttt{dp}\) 。
将 \(m\) 写成变进制表示,记 \(m=\sum\limits_{i=1}^nc_i\cdot A_i\) ,其中 \(0\le c_i<a_i\) , \(A_i=\prod_{j=1}^{i-1}a_j\) 为第 \(i\) 种货币的面值。
\(f_{i,j}\) 表示已经确定第 \(i\sim n\) 种货币的取法,还需要 \(j\cdot A_k\) 的面值的方案数。
先从第 \(i+1\) 层转移到第 \(i\) 层: \(f_{i,a_i\cdot j+c_i}\gets f_{i+1,j}\) 。
再考虑第 \(i\) 种货币选几个, \(f'_{i,j}=\sum_{k=0}^{b_i}f_{i,j+k}\) ,前缀和优化可以做到 \(\mathcal O(1)\) 转移。
接下来的问题是第二维 \(j\) 应该开多大。
如果 \(\sum_{k=1}^ib_kA_k<j\cdot A_i\) ,换言之取完后面所有货币都不足以填补漏洞,那么这个状态没有意义。
所以对于第 \(i\) 层,第二维开到 \(mx_i=\lfloor\frac{\sum_{k=1}^ib_kA_k}{A_i}\rfloor\) 即可,递推式 \(mx_{i+1}=\lfloor\frac{mx_i}{a_i}\rfloor+b_{i+1}\) 。
考虑单个 \(b_i\) 对状态总数 \(\sum mx_i\) 的贡献,它对 \(mx_i\) 贡献了 \(b_i\) ,对 \(mx_{i+1}\) 贡献不超过 \(\lfloor\frac{b_i}2\rfloor\) ,每升一层贡献至少减半。
因此 \(\sum mx_i\le\sum(b_i+\frac{b_i}2+\frac{b_i}4+\cdots)=2\sum b_i\) ,可以接受。
时间复杂度 \(\mathcal O(\log^2m+\sum b_i)\) ,前者为计算 \(c_k\) 的时间复杂度。
再考虑存在 \(a_i=1\) 的情况,转移方程同上。
由于每种面值至多 \(20\) 种,所以每升 \(20\) 层贡献至少减半,状态总数 \(\le 2\cdot 20\cdot\sum b_i\le 1.2\cdot 10^7\) 。
预处理 \(c_k\) 的代价有点高,考虑压位高精。以 \(10^9\) 进制存储 \(m\) ,每次除以 \(a_k\) ,则余数为 \(c_k\) 。
时间复杂度 \(\mathcal O\big((\frac{\log m}9)^2+40\sum b_i\big)\) 。
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+5,mod=1e9+7;
int l,n;
int a[maxn],b[maxn],c[maxn],mx[maxn];
char ch[maxn];
int pw[10],t[maxn];
int f[2][maxn],s[maxn];
int sum(int l,int r)
{
return l<=0?s[r]:(s[r]-s[l-1]+mod)%mod;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n-1;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
scanf("%s",ch),l=strlen(ch),reverse(ch,ch+l);
pw[0]=1;
for(int i=1;i<=9;i++) pw[i]=10*pw[i-1];
for(int i=0;i<l;i++) t[i/9]+=(ch[i]-'0')*pw[i%9];
l/=9;
for(int i=1;i<=n-1;i++)
{
if(a[i]==1) continue;
int cur=0;
for(int j=l;j>=0;j--)
{
long long tmp=t[j]+1ll*pw[9]*cur;
t[j]=tmp/a[i],cur=tmp%a[i];
}
c[i]=cur;
while(l>=0&&!t[l]) l--;
}
mx[1]=b[1];
for(int i=2;i<=n;i++) mx[i]=mx[i-1]/a[i-1]+b[i];
if(l>=1) printf("0\n"),exit(0);
c[n]=t[0],f[(n+1)&1][0]=1;
for(int i=n;i>=1;i--)
{
for(int j=0;j<=mx[i];j++) f[i&1][j]=0;
for(int j=0;j<=mx[i+1];j++) if(1ll*a[i]*j+c[i]<=mx[i]) f[i&1][a[i]*j+c[i]]=f[(i+1)&1][j];
s[0]=f[i&1][0];
for(int j=1;j<=mx[i];j++) s[j]=(s[j-1]+f[i&1][j])%mod;
for(int j=0;j<=mx[i];j++) f[i&1][j]=(s[min(j+b[i],mx[i])]-(j>=1?s[j-1]:0)+mod)%mod;
}
printf("%d\n",f[1][0]);
return 0;
}
本文来自博客园,作者:peiwenjun,转载请注明原文链接:https://www.cnblogs.com/peiwenjun/p/17090274.html
浙公网安备 33010602011771号