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; }