Atcoder Grand Contest 013 E Placing Squares

Placing Squares

Problem Statement

有一个长度为 n 的数轴,其中有 m 个交界位置被标记了。现在要用若干正方形去覆盖这个数 轴(参照下图),有 3 个规定:
1、正方形边长必须是正整数。
2、数轴要被恰好覆盖,即不能有空、不能有地方被多个正方形覆盖。
3、正方形的交界不能是被标记的位置。
定义一种方案的价值是所有正方形的面积的积。求所有合法不同方案的总价值和。

Data Constraint

n <=109 m <=105

Solution

先给出一个很简单的dp。
fi = i1j=0fj(ij)2
但这个dp显然会超时。
于是我们可以通过转换模型巧妙地处理这个平方。
x2 看成在长度为 x 的段内放一个黑球和一个白球的方案数(可以放同一位置)。
那接下来就简单了。
fi,j 表示做到了第 i 个位置,第i 个位置所属的段已放了 j 个球(j =0~2),那交界位置实际就是2无法转移到0,非交界位置是连续的一段,这一段的转移都是一样的,可以用矩阵乘法加快速幂完成。
时间复杂度 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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值