神仙题
首先转化成0/1串没有问题
然后1的个数有限?限制条件M<=5?
状压吧孩子
f[i][S]表示第i位S局面下方案数
所以可以按照题意转移
然后转移只和S有关&N<=1e15
矩阵加速吧孩子
开一个32*32的矩阵表示状态之间的转移qwq
(话说错位这个地方想的时间挺长的)
等下!这是个环?
难不成要枚举断点
考虑矩阵里面元素的定义
m[i][j]^k表示i状态到j状态经过k步的方案数
所以∑m[i][i]^n(i∈1->32)就是答案
最终复杂度O(2^5^3*lg(1e15)) 勉强能过
Code:
1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 #include<cmath>
5 #include<queue>
6 #include<iostream>
7 #define ms(a,b) memset(a,b,sizeof a)
8 #define rep(i,a,n) for(int i = a;i <= n;i++)
9 #define per(i,n,a) for(int i = n;i >= a;i--)
10 #define inf 2147483647
11 using namespace std;
12 typedef long long ll;
13 #define mod 1000000007
14 ll read() {
15 ll as = 0,fu = 1;
16 char c = getchar();
17 while(c < '0' || c > '9') {
18 if(c == '-') fu = -1;
19 c = getchar();
20 }
21 while(c >= '0' && c <= '9') {
22 as = as * 10 + c - '0';
23 c = getchar();
24 }
25 return as * fu;
26 }
27 struct Mt {
28 const static int M = 64;
29 ll a[M][M];
30 void init(int op) {
31 ms(a,0);
32 if(op == 1) rep(i,0,M-1) a[i][i] = 1;
33 }
34
35 Mt operator * (const Mt &o) const {
36 Mt tmp;tmp.init(0);
37 rep(i,0,M-1) rep(j,0,M-1) rep(k,0,M-1) {
38 tmp.a[i][j] = (tmp.a[i][j] + a[i][k] * o.a[k][j] % mod) % mod;
39 }
40 return tmp;
41 }
42
43 Mt operator ^ (ll b) const {
44 Mt r = *this;
45 Mt tmp;tmp.init(1);
46 while(b) {
47 if((b) & 1) tmp = tmp * r;
48 r = r * r;
49 (b) >>= 1;
50 }
51 return tmp;
52 }
53 }x;
54 //head
55 ll n,m,k,ans;
56 int stat[40];
57 #define low(x) ((x)&(-(x)))
58 int judgeI(ll x) {
59 int tmp = 0;
60 for(int i = x;i;i -= low(i)) tmp++;
61 return tmp;
62 }
63
64 int main() {
65 n = read(),m = read(),k = read();
66 int Max = 0;
67 rep(i,0,(1<<m)-1)
68 if(judgeI(i) <= k) stat[++Max] = i;
69 rep(i,1,Max) rep(j,1,Max) {
70 int xx = stat[i] % (1<<m-1);
71 int yy = stat[j] >> 1;
72 if(xx == yy) {
73 x.a[stat[i]][stat[j]] = 1;
74 }
75 }
76 x = x ^ (n);
77 rep(i,1,Max) ans = (ans + x.a[stat[i]][stat[i]]) % mod;
78 printf("%lld
",ans);
79 return 0;
80 }
最后自己还是能写出来矩阵加速的题还是比较开心的