【BZOJ2476】战场的数目 矩阵乘法
【BZOJ2476】战场的数目
Description
Input
输入文件最多包含25组测试数据,每个数据仅包含一行,有一个整数p(1<=p<=109),表示战场的图形周长。p=0表示输入结束,你的程序不应当处理这一行。
Output
对于每组数据,输出仅一行,即满足条件的战场总数除以987654321的余数。
Sample Input
7
8
9
10
0
8
9
10
0
Sample Output
0
2
0
9
2
0
9
HINT
湖南省第六届大学生计算机程序设计竞赛
题解:我们先将周长>>=1,那么设f[i]表示:长+宽=i时的方案数。由于我们很容易求出战场是一整个矩形的方案数,所以我们可以先不考虑战场不能为矩形这个条件。
然后思考如何转移,一开始想按列转移,推出一个优美的式子,但是化简不了,结果发现要按行转移。
考虑最下面一行,如果左右两端的高度都>1,那么我们可以直接将最后一行扔掉,方案数变成f[i-1]。
如果左右两端有一端高度>1,那么我们可以将那一列扔掉,方案数变成2*f[i-1]。
如果左右两端高度都是1,那么我们将两边都扔掉,但是这种情况在上面已经被计算2次了,所以方案数要减去2*f[i-2]。
所以f[i]=3*f[i-1]-f[i-2],矩乘搞一搞~
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | #include <cstdio> #include <iostream> #include <cstring> using namespace std; typedef long long ll; const ll mod=987654321; struct M { ll v[5][5]; M (){ memset (v,0, sizeof (v));} ll * operator []( int x) { return v[x];} M operator * (M a) { M ret; for ( int i=1;i<=3;i++) for ( int j=1;j<=3;j++) for ( int k=1;k<=3;k++) (ret[i][j]+=v[i][k]*a[k][j])%=mod; return ret; } }; M beg,ans,tr,x; void pm( int y) { ans=beg,x=tr; while (y) { if (y&1) ans=ans*x; x=x*x,y>>=1; } } int main() { tr[1][1]=3,tr[2][1]=-1,tr[2][3]=1,tr[1][2]=1; beg[1][1]=5,beg[1][2]=2,beg[1][3]=1; int p; while (1) { scanf ( "%d" ,&p); if (!p) return 0; if (p&1) { printf ( "0\n" ); continue ; } p>>=1; if (p<=3) { printf ( "0\n" ); continue ; } pm(p-4); printf ( "%lld\n" ,(ans[1][1]-(p-1)+2*mod)%mod); } return 0; } //8 10 0 |
| 欢迎来原网站坐坐! >原文链接<
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步