Placing Squares
Problem Statement
有一个长度为
n
的数轴,其中有
1、正方形边长必须是正整数。
2、数轴要被恰好覆盖,即不能有空、不能有地方被多个正方形覆盖。
3、正方形的交界不能是被标记的位置。
定义一种方案的价值是所有正方形的面积的积。求所有合法不同方案的总价值和。
Data Constraint
n
<=
Solution
先给出一个很简单的dp。
fi
=
∑i−1j=0fj∗(i−j)2
但这个dp显然会超时。
于是我们可以通过转换模型巧妙地处理这个平方。
把
x2
看成在长度为
x
的段内放一个黑球和一个白球的方案数(可以放同一位置)。
那接下来就简单了。
设
时间复杂度
O(m log n)
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,j,l) for(int i=j;i<=l;++i)
#define fd(i,j,l) for(int i=j;i>=l;--i)
using namespace std;
typedef long long ll;
const ll mo=1e9+7,N=11e4;
int a[N],n,m;
ll jz[3][3],lj[3][3],ans[3][3],keep[3][3];
inline int read()
{
int o=0; char ch=' ';
for(;ch<'0'||ch>'9';ch=getchar());
for(;ch>='0'&&ch<='9';ch=getchar())o=o*10+ch-48;
return o;
}
inline void fz()
{fo(i,0,2)fo(l,0,2)lj[i][l]=jz[i][l];}
inline void twice()
{
fo(i,0,2)fo(l,0,2){
keep[i][l]=0;
fo(j,0,2)keep[i][l]=keep[i][l]+lj[i][j]*lj[j][l];
}
fo(i,0,2)fo(l,0,2)lj[i][l]=keep[i][l]%mo;
}
inline void join()
{
fo(i,0,2)fo(l,0,2){
keep[i][l]=0;
fo(j,0,2)keep[i][l]=keep[i][l]+ans[i][j]*lj[j][l];
}
fo(i,0,2)fo(l,0,2)ans[i][l]=keep[i][l]%mo;
}
inline void count(int t)
{
fz();
for(;t;t>>=1,twice())
if(t&1)join();
}
int main()
{
cin>>n>>m;
fo(i,1,m)a[i]=read();
jz[0][0]=1; jz[0][1]=2; jz[0][2]=1; jz[2][0]=1;
jz[1][1]=1; jz[1][2]=1; jz[2][1]=2; jz[2][2]=2;
ans[0][0]=ans[1][1]=ans[2][2]=1;
fo(i,1,m){
count(a[i]-a[i-1]-1);
fz(); lj[2][0]=0; lj[2][2]=1; lj[2][0]=lj[2][1]=0;
join();
}
count(n-a[m]-1);
cout<<(ans[0][2]+ans[1][2]*2+ans[2][2])%mo;
}