对于 \(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 <cstdio> #include <cstring> #include <iostream> #include <algorithm> 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&&j<l[i]) || (b&&j>r[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); }