题目
给定前缀和值s和长为n(n<=1e5)的序列A,第i个数ai(1<=a1<=a2<=...<=an<=s<=1e18)
求满足以下条件的序列X的数量,答案对998244353取模
限制条件:
1. X序列中的每个元素都是正奇数
2. X序列中的数的和为s(s<=1e18)
3. 记X序列的前缀和序列为Y,Y中不包含给定序列a中的值
思路来源
Solution of ABC 258 Ex - Powerless233 的博客 - 洛谷博客
题解
感觉思路来源已经写的非常清楚了
感觉矩阵快速幂优化比较自然,
主要没有想到这个朴素的做法,
即
当然也学到了后面的前缀和限制的trick
1. 朴素算法+前缀和优化+矩阵快速幂优化
2. 给出矩阵快速幂转移式,并且有初始向量f[0]=1,s[-1]=0,s[-2]=0(边界条件)
3. 有前缀和不能为ai的限制,所以在n次矩阵快速幂转移时,手动给当前f[i]的值置为0
代码
//#include <bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<vector>
#include<map>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair<int,int> P;
#define fi first
#define se second
#define pb push_back
#define dbg(x) cerr<<(#x)<<":"<<x<<" ";
#define dbg2(x) cerr<<(#x)<<":"<<x<<endl;
#define SZ(a) (int)(a.size())
#define sci(a) scanf("%d",&(a))
#define pt(a) printf("%d",a);
#define pte(a) printf("%d\n",a)
#define ptlle(a) printf("%lld\n",a)
#define debug(...) fprintf(stderr, __VA_ARGS__)
using namespace std;
using namespace std;
typedef long long ll;
const int N=1e5+10,mod=998244353;
struct mat {
static const int MAXN=3;
ll c[MAXN][MAXN];
int m, n;
mat(){
memset(c, 0, sizeof(c));
m=n=MAXN;
}
mat(int a, int b) : m(a), n(b) {
memset(c, 0, sizeof(c));
}
void clear(){
memset(c, 0, sizeof(c));
}
mat operator * (const mat& temp) {
mat ans(m, temp.n);
for (int i = 0; i < m; i ++)
for (int j = 0; j < temp.n; j ++){
for (int k = 0; k < n; k ++){
ans.c[i][j] += c[i][k] * temp.c[k][j];
ans.c[i][j]%=mod;
}
}
return ans;
}
mat operator ^(ll n){
mat M(*this),ans(M.m, M.m);
for (int i = 0; i < M.m; i ++)
ans.c[i][i] = 1;
while (n > 0) {
if (n & 1) ans = ans * M;
M = M * M;
n >>= 1;
}
return ans;
}
}b,ans;
ll n,s,a[N];
int main(){
scanf("%lld%lld",&n,&s);
b.c[0][0]=b.c[0][2]=1;
b.c[1][0]=b.c[1][2]=1;
b.c[2][1]=1;
ans.c[0][0]=1;
rep(i,1,n){
scanf("%lld",&a[i]);
ans=(b^(a[i]-a[i-1]))*ans;
ans.c[0][0]=0;
}
ans=(b^(s-a[n]))*ans;
printf("%lld\n",ans.c[0][0]);
return 0;
}