[硫化铂]叮叮车

叮叮车

题目概述

在这里插入图片描述
在这里插入图片描述

题解

首先,我们考虑最小的矩阵覆盖的方案数该怎么计算。
首先,覆盖一个大小为 n n n的阶梯矩形的最小数量肯定是 n n n
因为不同的角肯定不可能出现在同一矩形内,至少需要 n n n个矩形,我们又很容易构造出一组只需要 n n n个的解,所以最小数量肯定为 n n n
那我们又该怎么计数呢?
我们可以借助 d p dp dp来统计,我们定义覆盖完前 i i i行,第 i i i行有 j j j个不同矩形的方案数为 d p i , j dp_{i,j} dpi,j
我们如果已经覆盖好了前 n − 1 n-1 n1行,现在准备覆盖第 n n n行,那么我们转移的时候就要枚举那些矩形有哪些不能延伸到第 n n n行,这些就只能有第 n n n行新产生的矩形来覆盖。
因为第 n n n行只能新产生一个,所以去掉的矩形必然是第 n n n行的一个后缀,有转移方程式:
d p i , j = ∑ k = j − 1 i − 1 d p i − 1 , k dp_{i,j}=\sum_{k=j-1}^{i-1} dp_{i-1,k} dpi,j=k=j1i1dpi1,k尝试把第二维变成 i − j i-j ij,那么有:
d p i , j = ∑ k = 0 min ⁡ ( i − 1 , j ) d p i − 1 , k dp_{i,j}=\sum_{k=0}^{\min(i-1,j)}dp_{i-1,k} dpi,j=k=0min(i1,j)dpi1,k再把这放到网格图上,不就是往后走不能降低,这不是卡塔兰数吗?可以发现,
d p i , j = ( i + j − 1 j ) − ( i + j − 1 j − 1 ) f ( n ) = ∑ i = 0 n − 1 d p i , j = ∑ i = 0 n − 1 ( ( n + i − 1 i ) − ( n + i − 1 i − 1 ) ) = ∑ i = 0 n − 1 ( n − 1 + i n − 1 ) − ∑ i = 0 n − 2 ( n + i n ) = ( 2 n − 1 n − 1 ) − ( 2 n − 1 n − 2 ) = 2 n − 1 ( 2 n − 1 n − 2 ) = 2 ( 2 n − 1 ) ! ( n − 1 ) ! ( n + 1 ) ! = ( 2 n ) ! ( n ! ) 2 ( n + 1 ) dp_{i,j}=\binom{i+j-1}{j}-\binom{i+j-1}{j-1}\\ f(n)=\sum_{i=0}^{n-1}dp_{i,j}=\sum_{i=0}^{n-1}\left(\binom{n+i-1}{i}-\binom{n+i-1}{i-1}\right)\\ =\sum_{i=0}^{n-1}\binom{n-1+i}{n-1}-\sum_{i=0}^{n-2}\binom{n+i}{n}=\binom{2n-1}{n-1}-\binom{2n-1}{n-2}\\ =\frac{2}{n-1}\binom{2n-1}{n-2}=\frac{2(2n-1)!}{(n-1)!(n+1)!}=\frac{(2n)!}{(n!)^2(n+1)} dpi,j=(ji+j1)(j1i+j1)f(n)=i=0n1dpi,j=i=0n1((in+i1)(i1n+i1))=i=0n1(n1n1+i)i=0n2(nn+i)=(n12n1)(n22n1)=n12(n22n1)=(n1)!(n+1)!2(2n1)!=(n!)2(n+1)(2n)!
我们要求的是 max ⁡ i = l r v p [ ( i + 1 ) f ( i ) ] \max_{i=l}^rv_p[(i+1)f(i)] maxi=lrvp[(i+1)f(i)],这恰好就乘上了一个 i + 1 i+1 i+1呀。
那我们记我们 g ( n ) = v 7 [ ( n + 1 ) f ( n ) ] g(n)=v_7[(n+1)f(n)] g(n)=v7[(n+1)f(n)],那么 g ( n ) = v 7 [ ( 2 n ) ! ( n ! ) 2 ] g(n)=v_7[\frac{(2n)!}{(n!)^2}] g(n)=v7[(n!)2(2n)!]
我们算的是里面 7 7 7的数量,显然可以枚举里面 7 7 7的倍数个数。
g ( n ) = ∑ i = 1 ∞ ⌊ 2 n 7 i ⌋ − 2 ⌊ n 7 i ⌋ = ∑ i = 1 ∞ [ 2 ( n % 7 i ) ⩾ 7 i ] g(n)=\sum_{i=1}^{\infty}\lfloor\frac{2n}{7^i}\rfloor-2\lfloor\frac{n}{7^i}\rfloor=\sum_{i=1}^{\infty}[2(n\%7^i)\geqslant7^i] g(n)=i=17i2n27in=i=1[2(n%7i)7i]可以发现,我们的答案一定是 log ⁡ 7 R \log_7 R log7R级别的。
上面的式子说的是,我们将一个数 7 7 7进制化了后,如果某一位后面的翻倍能够进位,就会有 1 1 1的贡献。
这不是可以数位 dp 吗?
我们定义 d p i , 0 / 1 , 0 / 1 , 0 / 1 dp_{i,0/1,0/1,0/1} dpi,0/1,0/1,0/1,表示转移到第 i i i位,是否触底,是否触顶,是否需要后面进位是的最大贡献。
转移方式只需要枚举后面加位的值,根据其关于 3 3 3的大小转移即可。
当然,最开始要将 l l l r r r变成 7 7 7进制。

时间复杂度 O ( log ⁡ 7 R ) O\left(\log_7 R\right) O(log7R),当然,要带一个不小的常数。

源码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
#define MAXN 20005
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
const int lim=1000000;
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1;}return t;}
int lena,lenb,dp[MAXN][2][2][2],ans,a[MAXN],b[MAXN],sta[MAXN],stak;
char astr[MAXN],bstr[MAXN];
int main(){
	freopen("dingdingcar.in","r",stdin);
	freopen("dingdingcar.out","w",stdout);
	scanf("%s\n%s",astr+1,bstr+1);
	lena=(int)strlen(astr+1);
	lenb=(int)strlen(bstr+1);
	memset(dp,-0x3f,sizeof(dp));int x=0;
	reverse(astr+1,astr+lena+1);
	reverse(bstr+1,bstr+lenb+1);
	for(int i=1;i<=lena;i++)a[i]=astr[i]-'0';
	for(int i=1;i<=lenb;i++)b[i]=bstr[i]-'0';
	for(int i=1;i<=lena;i+=6){stak++;for(int j=5;j>=0;j--)sta[stak]=10*sta[stak]+a[i+j];}lena=0;
	while(stak){
		for(int i=stak;i>0;i--)sta[i]=x*lim+sta[i],x=sta[i]%7,sta[i]/=7;
		a[++lena]=x;x=0;while(stak&&!sta[stak])stak--;
	}
	for(int i=1;i<=lenb;i+=6){stak++;for(int j=5;j>=0;j--)sta[stak]=10*sta[stak]+b[i+j];}lenb=0;
	while(stak){
		for(int i=stak;i>0;i--)sta[i]=x*lim+sta[i],x=sta[i]%7,sta[i]/=7;
		b[++lenb]=x;x=0;while(stak&&!sta[stak])stak--;
	}
	int len=max(lena,lenb);dp[len][1][1][1]=1;dp[len][1][1][0]=0;
	for(int i=len;i>0;i--)
		for(int S1=0;S1<2;S1++)
			for(int S2=0;S2<2;S2++){
				for(int j=0;j<7;j++){
					if((S1&&j<a[i])||(S2&&j>b[i]))continue;
					int s1=S1&(j==a[i]),s2=S2&(j==b[i]);
					if(j<3)dp[i-1][s1][s2][0]=max(dp[i-1][s1][s2][0],dp[i][S1][S2][0]),
						dp[i-1][s1][s2][1]=max(dp[i-1][s1][s2][1],dp[i][S1][S2][0]+1);
					if(j==3)dp[i-1][s1][s2][0]=max(dp[i-1][s1][s2][0],dp[i][S1][S2][0]),
						dp[i-1][s1][s2][1]=max(dp[i-1][s1][s2][1],dp[i][S1][S2][1]+1);
					if(j>3)dp[i-1][s1][s2][0]=max(dp[i-1][s1][s2][0],dp[i][S1][S2][1]),
						dp[i-1][s1][s2][1]=max(dp[i-1][s1][s2][1],dp[i][S1][S2][1]+1);	
				}
			}
	for(int S1=0;S1<2;S1++)
		for(int S2=0;S2<2;S2++)
			ans=max(ans,dp[0][S1][S2][0]);
	printf("%d\n",ans);
	return 0;
}

谢谢!!!

posted @ 2022-04-05 18:06  StaroForgin  阅读(9)  评论(0)    收藏  举报  来源