[省选集训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);
}

相关