Discription
在思考一道计算题。
给你一个尺寸为 的长条,你可以在上面切很多刀,要求竖直地切并且且完后每块的长度都是整数。
在这种限制下其实只有 个位置可以切。
对于一种切的方案,假如切完后每块的宽度分别是:,那么该种方案对应
的完美值为:
那么问题来了,给出 个位置不能切(如果用 表示一个位置,那么切完该位置后长条变为 和
两块),那么所有合法切法对应的完美值的和是多少呢?(只需要输出模 的结果)
Input
第 行,有 个整数:,表示长条的总长度及不能切的位置数
第 行,有 个整数: 表示不能切的位置。
Output
输出 行,包含 个整数,表示满足要求的所有切法对应的完美值和。(对 取模后的结果)
Note
• 对于 的数据,有 。
• 对于 的数据,有 。
• 对于 的数据,有 ,且
很显然可以看出柿子
然后答案就为
由于很大
所以考虑用矩阵快速幂优化转移
先想想怎么转移
定义向量如下:
然后考虑从转移到
转移矩阵就是
自己推一推吧…
注意第二项和第三项当时贡献的值是因为,所以的范围实质上是.为了统一就写成了.
考虑这个地方不能切,我们就强制把这个位置的值设为就行了.
那么不能切的地方的转移,就只用把第一项累加的系数去掉就行了.第一行也就变成了,那么不能切的地方的转移矩阵就如下:
详细见代码
CODE
#include<bits/stdc++.h>
using namespace std;
inline void read(int &num) {
char ch; int flg = 1; while(!isdigit(ch=getchar()))if(ch=='-')flg = -flg;
for(num=0; isdigit(ch); num=num*10+ch-'0', ch=getchar()); num*=flg;
}
const int MAXN = 1e5+5;
const int mod = 1e9+7;
struct mat {
int a[3][3];
mat() { memset(a,0,sizeof a); }
inline void init1() {
a[0][0] = 2; a[0][1] = 2; a[0][2] = 1;
a[1][0] = 1; a[1][1] = 1; a[1][2] = 0;
a[2][0] = 1; a[2][1] = 2; a[2][2] = 1;
}
inline void init2() {
a[0][0] = 1; a[0][1] = 0; a[0][2] = 0;
a[1][0] = 1; a[1][1] = 1; a[1][2] = 0;
a[2][0] = 1; a[2][1] = 2; a[2][2] = 1;
}
inline mat operator *(const mat &o)const {
mat re;
for(int k = 0; k < 3; ++k)
for(int i = 0; i < 3; ++i) if(a[i][k])
for(int j = 0; j < 3; ++j) if(o.a[k][j])
re.a[i][j] = (re.a[i][j] + 1ll * a[i][k] * o.a[k][j] % mod) % mod;
return re;
}
inline mat operator ^(int b)const {
mat A = *this, re;
re.a[0][0] = re.a[1][1] = re.a[2][2] = 1;
while(b) {
if(b & 1) re = re * A;
A = A * A; b >>= 1;
}
return re;
}
}ans, trans1, trans2;
int N, M, pos[MAXN];
int main() {
freopen("count.in", "r", stdin);
freopen("count.out", "w", stdout);
scanf("%d%d", &N, &M);
for(int i = 1; i <= M; ++i)
scanf("%d", &pos[i]);
ans.a[0][0] = 1;
trans1.init1();
trans2.init2();
for(int i = 1; i <= M; ++i)
ans = (trans1^(pos[i]-pos[i-1]-1)) * ans, ans = trans2 * ans;
ans = (trans1^(N-pos[M])) * ans;
printf("%d
", ans.a[2][0]);
}
妈妈我终于会矩阵快速幂了!!!