[省选集训2022] 叮叮车
一、题目
对于 \(i\in[l,r]\),\({2i\choose i}\) 最多含有的 质因子 \(7\) 的个数 是多少?
\(l\leq r\leq 10^{10000}\)
二、解法
考虑 \({2n\choose n}\) 含有质因数 \(7\) 的个数是:
\[\sum_{i=0}^{\infty}\lfloor\frac{2n}{7^i}\rfloor-2\lfloor\frac{n}{7^i}\rfloor=\sum_{i=0}^{\infty}[2(n\bmod 7^i)\geq 7^i] \]我们先把 \(l,r\) 都转化成 \(7\) 进制,那么如果某个数的后 \(i\) 位乘 \(2\) 可以进位,就说明产生了一个贡献。设 \(dp[i][0/1][0/1][0/1]\) 表示考虑了前 \(i\) 位,是否抵到下界,是否顶到上界,乘 \(2\) 之后一定进位 \(/\) 一定不进位,的最大贡献。
转移就考虑枚举当前这一位选了什么,然后按照和 \(3\) 的大小关系来分类讨论即可。
#include
#include
#include
#include
using namespace std;
const int M = 20005;
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,m,ans,l[M],r[M],s[M],dp[M][2][2][2];char t[M];
void upd(int &x,int y) {x=max(x,y);}
void zxy(int *a)
{
scanf("%s",t+1);m=strlen(t+1);n=0;
for(int i=1;i<=m;i++) s[i]=t[i]-'0';
reverse(s+1,s+1+m);
while(m)
{
int sum=0;
for(int i=m;i>=1;i--)
s[i]+=10*sum,sum=s[i]%7,s[i]/=7;
a[++n]=sum;
while(s[m]==0 && m) m--;
}
}
int main()
{
freopen("dingdingcar.in","r",stdin);
freopen("dingdingcar.out","w",stdout);
zxy(l);zxy(r);
memset(dp,-0x3f,sizeof dp);
dp[n][1][1][0]=0;
dp[n][1][1][1]=1;
for(int i=n;i>=1;i--) for(int a=0;a<2;a++)
for(int b=0;b<2;b++) for(int j=0;j<7;j++)
{
if((a&&jr[i])) continue;
int A=a&(j==l[i]),B=b&(j==r[i]);
if(j<3)
{
upd(dp[i-1][A][B][0],dp[i][a][b][0]);
upd(dp[i-1][A][B][1],dp[i][a][b][0]+1);
}
if(j==3)
{
upd(dp[i-1][A][B][0],dp[i][a][b][0]);
upd(dp[i-1][A][B][1],dp[i][a][b][1]+1);
}
if(j>3)
{
upd(dp[i-1][A][B][0],dp[i][a][b][1]);
upd(dp[i-1][A][B][1],dp[i][a][b][1]+1);
}
}
for(int a=0;a<2;a++) for(int b=0;b<2;b++)
upd(ans,dp[0][a][b][0]);
printf("%d\n",ans);
}