分析
在比赛中没有做出了,对矩阵的掌握还是太菜了。先对与原问题考虑。我们发现这个问题其实并不好考虑,其中涉及的状态太多,但是考虑一下用全部方案减去不合法的方案来计算。 。先看前面的 。这里有两种理解。
- 考虑在每个点后面是否划分那么总的方案数为 。
- 也可以用插板法来理解,那么我们总的方案数为 。
那么现在问题就是如何求出 。先考虑一个朴素的 ,令 凑成 时的不合法数量。那么 。因为 ,所以一个数的影响不会超过 。这个给我们矩阵优化的基础。那么用矩阵求出 ,复杂度为 ,代码的细节如有不理解的可以私聊啊 。
代码
#include<bits/stdc++.h> using namespace std; #define LL long long LL read() { LL x = 0,f = 0;char ch = getchar(); while(!isdigit(ch)) {if(ch == '-')f = 1;ch = getchar();} while(isdigit(ch)) {x = x * 10 + ch - '0';ch = getchar();} return f ? -x : x; } LL n,p,k,Max = 0; LL qpow(LL a,LL b) { LL x = 1; for(;b;b>>=1,a=(a*a)%p) if(b&1) x = (x*a)%p; return x; } struct Sqr{ LL s[110][110]; Sqr() {memset(s,0,sizeof(s));} Sqr operator * (const Sqr A) const{ Sqr C; for(int i = 0;i < Max;i++) { for(int j = 0;j < Max;j++) { for(int k = 0;k < Max;k++) { C.s[i][j] = (C.s[i][j] + (s[i][k] * A.s[k][j] % p)) % p; } } } return C; } }ans,res; int main() { n = read();p = read();k = read(); for(int i = 1;i <= k;i++) { LL val = read(); res.s[val - 1][0] = 1;Max = max(1LL * val,Max); } for(int i = 0;i < Max - 1;i++) res.s[i][i+1] = 1; LL b = n;ans.s[0][0] = 1; while(b) { if(b&1) ans = ans * res; b>>=1;res = res * res; } printf("%lld\n",((qpow(2,n-1)-ans.s[0][0])%p+p)%p); return 0; }
后记
我还是把题解写清楚一点吧,别骂了别骂了。