国王之手不喜欢巨人 ,巨人也不喜欢国王之手,但他们有一个共同点:都不喜欢炼金师。
——Deadcells:王座之间
一个阶梯状图形,第一行靠右有 n n n 个色块,第二行靠右有 n − 1 n-1 n−1 个色块……一直到第 n n n 行。令 f ( n ) f(n) f(n) 等于用最少的矩形不重叠地刚好覆盖所有色块的方案数。
定义 V ( x ) V(x) V(x) 为 x x x 的质因数分解中 7 的幂。
求 max i = l r V ( ( i + 1 ) f ( i ) ) \max_{i=l}^r V((i+1)f(i)) maxi=lrV((i+1)f(i)) 。
l ≤ r ≤ 1 0 10000 l\leq r\leq 10^{10000} l≤r≤1010000 。
这道题,懒人是很难做出来的。
我们先分析函数 f ( n ) f(n) f(n) ,容易发现 f ( n ) f(n) f(n) 的递推式:
f ( n ) = ∑ i = 1 n f ( i − 1 ) f ( n − i ) f(n)=\sum_{i=1}^{n} f(i-1)f(n-i) f(n)=i=1∑nf(i−1)f(n−i)
这个递推式和卡塔兰数的递推式一模一样,由于开头的几项也一样,所以 f ( n ) f(n) f(n) 就是卡塔兰数。
如果我们列出卡塔兰数的这个表达式 f ( n ) = ( 2 n n ) − ( 2 n n − 1 ) f(n)={2n\choose n}-{2n\choose n-1} f(n)=(n2n)−(n−12n) ,我们是做不出来的。所以记忆不同的一些表达式总是很有必要:
f ( n ) = ( 2 n n ) − ( 2 n n − 1 ) = ( 2 n n ) − n n + 1 ⋅ ( 2 n n ) = ( 2 n n ) n + 1 f(n)={2n\choose n}-{2n\choose n-1}={2n\choose n}-\frac{n}{n+1}\cdot {2n\choose n} =\frac{2n\choose n}{n+1} f(n)=(n2n)−(n−12n)=(n2n)−n+1n⋅(n2n)=n+1(n2n)
代进去,刚好
max i = l r V ( ( i + 1 ) f ( i ) ) = max i = l r V ( ( 2 i i ) ) = max i = l r V ( ( 2 i ) ! ) − 2 V ( i ! ) \max_{i=l}^r V((i+1)f(i))=\\~\\ \max_{i=l}^r V\left({2i\choose i}\right)= \\\max_{i=l}^r V((2i)!)-2V(i!) i=lmaxrV((i+1)f(i))= i=lmaxrV((i2i))=i=lmaxrV((2i)!)−2V(i!)
接下来冷静分析 V ( x ! ) V(x!) V(x!):
V ( x ! ) = ∑ i = 1 ⌊ x 7 i ⌋ V(x!)=\sum_{i=1} \left\lfloor \frac{x}{7^i} \right\rfloor V(x!)=i=1∑⌊7ix⌋
我们把 x x x 表示成 7 7 7 进制数 ∑ i = 0 a i 7 i \sum_{i=0} a_i7^i ∑i=0ai7i 就好办了
V ( x ! ) = ∑ i = 0 a i 7 i − 1 − 1 6 = ∑ i = 0 ( a i 7 i − 1 − a i ) 6 = ⌊ x / 6 ⌋ − ∑ i = 0 a i 6 V(x!)=\sum_{i=0} a_i\frac{7^{i-1}-1}{6}=\frac{\sum_{i=0} (a_i7^{i-1}-a_i)}{6}=\frac{\lfloor x/6\rfloor-\sum_{i=0}a_i}{6} V(x!)=i=0∑ai67i−1−1=6∑i=0(ai7i−1−ai)=6⌊x/6⌋−∑i=0ai
我们再令 S x = ∑ i = 0 a i S_x=\sum_{i=0}a_i Sx=∑i=0ai ,答案式子就很直观了
max i = l r V ( ( 2 i ) ! ) − 2 V ( i ! ) = max i = l r 2 S i − S 2 i 6 \max_{i=l}^r V((2i)!)-2V(i!)=\max_{i=l}^r \frac{2S_i-S_{2i}}{6} i=lmaxrV((2i)!)−2V(i!)=i=lmaxr62Si−S2i
由于 S i S_i Si 是七进制下每一位的和,所以最终答案不超过两万!
最后我们可以用数位DP来解决,除了是否抵达上/下界,还要记录 2 i 2i 2i 后续是否进位,不然无法处理 S 2 i S_{2i} S2i 。
由于需要进制转换,所以用压位高精的话,时间是极小常数的 O ( ∣ r ∣ 2 ) O(|r|^2) O(∣r∣2) 。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define MAXN 10005
#define LL long long
#define ULL unsigned long long
#define ENDL putchar('\n')
#define DB double
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
int xchar() {
static const int maxn = 1000000;
static char b[maxn];
static int pos = 0,len = 0;
if(pos == len) pos = 0,len = fread(b,1,maxn,stdin);
if(pos == len) return -1;
return b[pos ++];
}
//#define getchar() xchar()
LL read() {
LL f = 1,x = 0;int s = getchar();
while(s < '0' || s > '9') {if(s<0)return -1;if(s=='-')f=-f;s = getchar();}
while(s >= '0' && s <= '9') {x = (x<<1) + (x<<3) + (s^48);s = getchar();}
return f*x;
}
void putpos(LL x) {if(!x)return ;putpos(x/10);putchar((x%10)^48);}
void putnum(LL x) {
if(!x) {putchar('0');return ;}
if(x<0) putchar('-'),x = -x;
return putpos(x);
}
void AIput(LL x,int c) {putnum(x);putchar(c);}
int n,m,s,o,k;
char ll[MAXN],rr[MAXN];
const int B = 100000000;
struct it{
vector<int> s;
int n;
it(){s.resize(2); s[n=1] = 0;}
it(int x){s.resize(2); s[n=1] = x;}
int MD(int x) {
int as = 0;
for(int i = n;i > 0;i --) {
as = (as*B%x + s[i]) % x;
}return as;
}
bool emp() {return n == 1 && s[1] == 0;}
};
it operator + (it a,it b) {
int m = 0;
for(int i = 1;i <= a.n || i <= b.n || m;i ++) {
if(i >= a.s.size()) a.s.push_back(0);
if(i > a.n) a.s[++ a.n] = 0;
if(i >= b.s.size()) b.s.push_back(0);
if(i > b.n) b.s[++ b.n] = 0;
a.s[i] = a.s[i] + b.s[i] + m;
if(a.s[i] > B) a.s[i] -= B,m = 1;
}
return a;
}
it operator * (it a,it b) {
it c; if(a.n > b.n) swap(a,b);
for(int i = 1;i <= a.n;i ++) {
int m = 0;
for(int j = 1;j <= b.n || m;j ++) {
if(j >= b.s.size()) b.s.push_back(0);
if(j > b.n) b.s[++ b.n] = 0;
if(i+j-1 >= c.s.size()) c.s.push_back(0);
if(i+j-1 > c.n) c.s[++ c.n] = 0;
LL nm = (c.s[i+j-1] + a.s[i]*1ll*b.s[j] + m);
m = nm/B; c.s[i+j-1] = nm%B;
}
}return c;
}
it operator / (it a,int b) {
LL m = 0;
for(int i = a.n;i > 0;i --) {
m = m*B + a.s[i];
a.s[i] = m / b; m %= b;
} while(a.n > 1 && a.s[a.n] == 0) a.n --;
return a;
}
int a[MAXN<<2],b[MAXN<<2];
int dp[MAXN<<2][2][2][2];
int main() {
freopen("dingdingcar.in","r",stdin);
freopen("dingdingcar.out","w",stdout);
it L,R;
scanf("%s",ll + 1);
n = strlen(ll + 1);
scanf("%s",rr + 1);
m = strlen(rr + 1);
for(int i = 1;i <= n;i ++) L = L * it(10) + it(ll[i]-'0');
for(int i = 1;i <= m;i ++) R = R * it(10) + it(rr[i]-'0');
n = 0; m = 0;
while(!L.emp()) a[++ n] = L.MD(7),L = L/7;
while(!R.emp()) b[++ m] = R.MD(7),R = R/7;
int le = max(n,m);
for(int s = 0;s < 2;s ++) {
for(int o = 0;o < 2;o ++) {
for(int k = 0;k < 2;k ++) {
dp[le+2][s][o][k] = -0x3f3f3f3f; // 44 65
}
}
}
dp[le+2][0][0][0] = 0;
for(int i = le+1;i > 0;i --) {
for(int s = 0;s < 2;s ++) {
for(int o = 0;o < 2;o ++) {
for(int k = 0;k < 2;k ++) {
dp[i][s][o][k] = -0x3f3f3f3f;
}
}
}
for(int s = 0;s < 2;s ++) {
for(int o = 0;o < 2;o ++) {
int nl = (s ? 0:a[i]),nr = (o ? 6:b[i]);
for(int x = nl;x <= nr;x ++) {
bool k1 = ((x<<1)>=7 ? 1:0),k2 = ((x<<1|1)>=7 ? 1:0);
bool A = (s || x > a[i]),B = (o || x < b[i]);
dp[i][A][B][0] = max(dp[i][A][B][0],dp[i+1][s][o][k1] + x*2 - (x*2%7));
dp[i][A][B][1] = max(dp[i][A][B][1],dp[i+1][s][o][k2] + x*2 - ((x<<1|1)%7));
}
}
}
}
int ans = 0;
for(int s = 0;s < 2;s ++) {
for(int o = 0;o < 2;o ++) {
ans = max(ans,dp[1][s][o][0]);
}
}
ans /= 6;
AIput(ans,'\n');
return 0;
}