跳到主要内容

题解:P9416 [POI2021-2022R1] Domino

· 阅读需 2 分钟
lailai
Blogger

原题链接

解题思路

  1. ana_n 表示斐波那契数列第 n+1n+1 项数值:
an={1n1an1+an2elsea_n=\begin{cases} 1 & n\le1 \\ a_{n-1}+a_{n-2} & \text{else} \end{cases}
  1. 使用 1×21\times 2(横向)或 2×12\times 1(纵向)的方块来覆盖 2×n2\times n 矩形的所有格子:
  • 有两种填充方式,如图所示:

  • 如果使用横向方块,则两行必须都是横向方块,否则两侧会有奇数个格子,无法填满。

  • 这两种填充方式分别覆盖了 11 列和 22 列,总共要覆盖 nn 列,很容易发现方案数是 ana_n

  1. 我们可以占用 2×(k1)2\times(k-1) 个格子(每两个一组),将整个矩形划分为 kk 部分。根据乘法原理,总方案数 mm 等于每部分方案数的乘积。

  2. 原问题可以等价为:将 mm 分解为若干个 aia_i 的乘积,每次使用 aia_i 的成本是 i+1i+1(因为有 11 列格子被占用),我们需要求出最小的成本 1-1(最后一部分不需要占用格子)。

  3. 由于 a90>1018a_{90}>10^{18},可以采用递归枚举的解决此问题。

参考代码

#include <bits/stdc++.h>
using namespace std;

using ll=long long;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int N=105;
ll a[N]={1,1};
ll ans=inf;
void f(ll x,ll s)
{
if(x<=1)
{
ans=min(ans,s-1);
return;
}
for(int i=2;i<=90;i++)
{
if(x%a[i]==0)
{
ll u=x,v=s;
while(u%a[i]==0)
{
u/=a[i];
v+=i+1;
}
f(u,v);
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
for(int i=2;i<=90;i++)
{
a[i]=a[i-1]+a[i-2];
}
ll m;
cin>>m;
f(m,0);
if(m==1)
{
cout<<1<<'\n';
}
else if(ans==inf)
{
cout<<"NIE"<<'\n';
}
else
{
cout<<ans<<'\n';
}
return 0;
}