AGC013 E Placing Squares——模型转化+矩阵乘法

题目:https://atcoder.jp/contests/agc013/tasks/agc013_e

边长的平方,可以看做是在该范围内放两个不同的球的方案数。两个球可以重合。

题意变成:给长为 n 的段放若干隔板,最前/后面有隔板,指定位置不能放隔板,相邻隔板间放两个不同球的方案数。

dp[ 0/1/2 ] 表示从上一个隔板至今已经放了几个球。把 “能放隔板” 和 “不能放隔板” 写成两个转移矩阵,就能转移了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
  while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
  return fx?ret:-ret;
}
const int N=1e5+5,mod=1e9+7;
int n,m,x[N];
struct Mtr{
  int a[3][3];
  Mtr(){memset(a,0,sizeof a);}
  Mtr operator* (const Mtr &b)const
  {
    Mtr c;
    for(int i=0;i<3;i++)
      for(int k=0;k<3;k++)
    for(int j=0;j<3;j++)
      c.a[i][j]=(c.a[i][j]+(ll)a[i][k]*b.a[k][j])%mod;
    return c;
  }
  void init()
  {
    for(int i=0;i<3;i++)for(int j=0;j<3;j++)a[i][j]=1;
    a[0][1]=a[2][1]=a[2][2]=2; a[1][0]=0;
  }
}ans,b0,b1,tp,one;
void pw(int n)
{
  b0=one; tp.init();
  while(n)
    { if(n&1)b0=b0*tp; tp=tp*tp; n>>=1;}
}
int main()
{
  n=rdn();m=rdn();
  for(int i=1;i<=m;i++)x[i]=rdn(); x[++m]=n;
  b1.init(); b1.a[2][1]=b1.a[2][0]=0; b1.a[2][2]=1;
  for(int i=0;i<3;i++)one.a[i][i]=1;
  ans.a[0][0]=1; pw(x[1]); ans=ans*b0;
  for(int i=1;i<m;i++)
    {
      ans=ans*b1;
      pw(x[i+1]-x[i]-1); ans=ans*b0;
    }
  printf("%d\n",ans.a[0][2]);
  return 0;
}

 

posted on 2019-06-11 16:56  Narh  阅读(333)  评论(0编辑  收藏  举报

导航