CodeForces 1152F2 Neko Rules the Catniverse (Large Version)

题目链接:http://codeforces.com/problemset/problem/1152/F2

题目大意

  见http://codeforces.com/problemset/problem/1152/F1,此题 n 最大能到 109

分析

  在 F1 的基础上,我们发现 dp[i + 1] 数组的每个值均可以通过 dp[i] 数组的有限几个数求得,而 dp[i + 2] 数组的每个值也均可以通过 dp[i + 1] 数组相同位置的有限几个数求得,于是我们可以考虑用矩阵快速幂来求 dp[n]。
  由于 dp 数组的第二维和第三维数值并不是特别大,我们可以把 dp 数组的后两个维度压制成一个维度,于是 dp[i][j][sta] 就变成 dp[i][cur],其中 cur = j * (1 << m) + sta。
  假设 dp[i][cur] 对某一个 dp[i + 1][newcur] 有贡献,根据上一题的帖子,有两种可能:
  1. 不访问:dp[i + 1][newcur] += dp[i][cur]。
  2. 访问:dp[i + 1][newcur] += dp[i][cur] * (1 + 后m个星球被访问过的星球个数)。

  定义 base 矩阵是我们所要构造的矩阵,设 base[cur][newcur] 代表某一个状态 cur 对一个新状态 newcur 所做贡献的系数,于是有:

  1. 不访问:base[cur][newcur] = 1。
  2. 访问:base[cur][newcur] =  (1 + 后m个星球被访问过的星球个数)。
  3. 其他(cur 压根不可能变成 newcur):base[cur][newcur] = 0。
  于是 $dp[i + 1][newcur] = sum_{cur = 0}^{maxCur} dp[i][cur] * base[cur][newcur]$。
  根据这个式子可以构造 dp 矩阵如下(以 k = 1, m = 1 为例):
$$
dp(i) = egin{bmatrix}
dp[i][0] & dp[i][1] & dp[i][2] & dp[i][3]
end{bmatrix} 
$$
  相应 base 系数矩阵如下:

$$
base = egin{bmatrix}
base[0][0] & base[0][1] & base[0][2] & base[0][3] \
base[1][0] & base[1][1] & base[1][2] & base[1][3] \
base[2][0] & base[2][1] & base[2][2] & base[2][3] \
base[3][0] & base[3][1] & base[3][2] & base[3][3]
end{bmatrix}
$$

  base 矩阵填上数后为:

$$
base = egin{bmatrix}
1 & 1 & 0 & 0 \
0 & 0 & 0 & 0 \
0 & 0 & 1 & 1 \
1 & 2 & 0 & 0
end{bmatrix}
$$

  于是有:

$$
egin{align*}
dp(i) &= dp(i - 1) * base \
dp(n) &= dp(0) * base^{n}
end{align*}
$$

  不知道关于矩阵怎么构造的说的明不明白,有不足的地方还请指出。
  PS:如果不压制维度,那么 base 矩阵就要弄四维的了,四维矩阵乘法反正我是不会。

代码如下

  时间复杂度:$O(log n*(k*2^m)^3)$

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3  
  4 #define INIT() ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
  5 #define Rep(i,n) for (int i = 0; i < (n); ++i)
  6 #define For(i,s,t) for (int i = (s); i <= (t); ++i)
  7 #define rFor(i,t,s) for (int i = (t); i >= (s); --i)
  8 #define ForLL(i, s, t) for (LL i = LL(s); i <= LL(t); ++i)
  9 #define rForLL(i, t, s) for (LL i = LL(t); i >= LL(s); --i)
 10 #define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i)
 11 #define rforeach(i,c) for (__typeof(c.rbegin()) i = c.rbegin(); i != c.rend(); ++i)
 12  
 13 #define pr(x) cout << #x << " = " << x << "  "
 14 #define prln(x) cout << #x << " = " << x << endl
 15  
 16 #define LOWBIT(x) ((x)&(-x))
 17  
 18 #define ALL(x) x.begin(),x.end()
 19 #define INS(x) inserter(x,x.begin())
 20  
 21 #define ms0(a) memset(a,0,sizeof(a))
 22 #define msI(a) memset(a,inf,sizeof(a))
 23 #define msM(a) memset(a,-1,sizeof(a))
 24 
 25 #define MP make_pair
 26 #define PB push_back
 27 #define ft first
 28 #define sd second
 29  
 30 template<typename T1, typename T2>
 31 istream &operator>>(istream &in, pair<T1, T2> &p) {
 32     in >> p.first >> p.second;
 33     return in;
 34 }
 35  
 36 template<typename T>
 37 istream &operator>>(istream &in, vector<T> &v) {
 38     for (auto &x: v)
 39         in >> x;
 40     return in;
 41 }
 42  
 43 template<typename T1, typename T2>
 44 ostream &operator<<(ostream &out, const std::pair<T1, T2> &p) {
 45     out << "[" << p.first << ", " << p.second << "]" << "
";
 46     return out;
 47 }
 48 
 49 inline int gc(){
 50     static const int BUF = 1e7;
 51     static char buf[BUF], *bg = buf + BUF, *ed = bg;
 52     
 53     if(bg == ed) fread(bg = buf, 1, BUF, stdin);
 54     return *bg++;
 55 } 
 56 
 57 inline int ri(){
 58     int x = 0, f = 1, c = gc();
 59     for(; c<48||c>57; f = c=='-'?-1:f, c=gc());
 60     for(; c>47&&c<58; x = x*10 + c - 48, c=gc());
 61     return x*f;
 62 }
 63  
 64 typedef long long LL;
 65 typedef unsigned long long uLL;
 66 typedef pair< double, double > PDD;
 67 typedef pair< int, int > PII;
 68 typedef pair< string, int > PSI;
 69 typedef set< int > SI;
 70 typedef vector< int > VI;
 71 typedef map< int, int > MII;
 72 typedef pair< LL, LL > PLL;
 73 typedef vector< LL > VL;
 74 typedef vector< VL > VVL;
 75 const double EPS = 1e-10;
 76 const LL inf = 0x7fffffff;
 77 const LL infLL = 0x7fffffffffffffffLL;
 78 const LL mod = 1e9 + 7;
 79 const int maxN = 1e5 + 7;
 80 const LL ONE = 1;
 81 const LL evenBits = 0xaaaaaaaaaaaaaaaa;
 82 const LL oddBits = 0x5555555555555555;
 83 
 84 void add_mod(LL &a, LL b) {
 85     a = (a + b) % mod;
 86 }
 87 
 88 struct Matrix{
 89     int row, col;
 90     LL MOD;
 91     VVL mat;
 92     
 93     Matrix(int r, int c, LL p = mod) : row(r), col(c), MOD(p) { 
 94         mat.assign(r, VL(c, 0));
 95     }
 96     Matrix(const Matrix &x, LL p = mod) : MOD(p){
 97         mat = x.mat;
 98         row = x.row;
 99         col = x.col;
100     }
101     Matrix(const VVL &A, LL p = mod) : MOD(p){
102         mat = A;
103         row = A.size();
104         col = A[0].size();
105     }
106     
107     // x * 单位阵 
108     inline void E(int x = 1) {
109         assert(row == col);
110         Rep(i, row) mat[i][i] = x;
111     }
112     
113     inline VL& operator[] (int x) {
114         assert(x >= 0 && x < row);
115         return mat[x];
116     }
117     
118     inline Matrix operator= (const VVL &x) {
119         row = x.size();
120         col = x[0].size();
121         mat = x;
122         return *this;
123     }
124     
125     inline Matrix operator+ (const Matrix &x) {
126         assert(row == x.row && col == x.col);
127         Matrix ret(row, col);
128         Rep(i, row) {
129             Rep(j, col) {
130                 ret.mat[i][j] = mat[i][j] + x.mat[i][j];
131                 ret.mat[i][j] %= MOD;
132             }
133         }
134         return ret;
135     }
136     
137     inline Matrix operator* (const Matrix &x) {
138         assert(col == x.row);
139         Matrix ret(row, x.col);
140         Rep(k, x.col) {
141             Rep(i, row) {
142                 if(mat[i][k] == 0) continue;
143                 Rep(j, x.col) {
144                     ret.mat[i][j] += mat[i][k] * x.mat[k][j];
145                     ret.mat[i][j] %= MOD;
146                 }
147             }
148         }
149         return ret;
150     }
151     
152     inline Matrix operator*= (const Matrix &x) { return *this = *this * x; }
153     inline Matrix operator+= (const Matrix &x) { return *this = *this + x; }
154     
155     inline void print() {
156         Rep(i, row) {
157             Rep(j, col) {
158                 cout << mat[i][j] << " ";
159             }
160             cout << endl;
161         }
162     }
163 };
164 
165 // 矩阵快速幂,计算x^y 
166 inline Matrix mat_pow_mod(Matrix x, LL y) {
167     Matrix ret(x.row, x.col);
168     ret.E();
169     while(y){
170         if(y & 1) ret *= x;
171         x *= x;
172         y >>= 1;
173     }
174     return ret;
175 }
176 
177 int n, k, m, maxSta; 
178 LL ans;
179 
180 int toId(int j, int sta) {
181     return j * maxSta + sta;
182 }
183 
184 int main(){
185     INIT(); 
186     cin >> n >> k >> m;
187     maxSta = 1 << m; 
188     Matrix dp(1, (k + 1) * maxSta);
189     dp.mat[0][0] = 1; 
190     Matrix base((k + 1) * maxSta, (k + 1) * maxSta);
191     
192     // 构造base矩阵 
193     Rep(j, k + 1) {
194         Rep(sta, maxSta) {
195             int newsta = (sta << 1) % maxSta;
196             int cur = toId(j, sta), newcur = toId(j, newsta);
197             
198             // 不选 i + 1 个星球从cur->newcur的状态变化 
199             base.mat[cur][newcur] = 1;
200             // 选 i + 1 个星球从cur->newcur的状态变化 
201             if (j < k) {
202                 newcur = toId(j + 1, newsta | 1);
203                 base.mat[cur][newcur] = __builtin_popcount(sta) + 1;
204             }
205         }
206     }
207     
208     base = mat_pow_mod(base, n);
209     dp *= base;
210     
211     Rep(sta, maxSta) add_mod(ans, dp.mat[0][toId(k, sta)]);
212     cout << ans << endl;
213     return 0;
214 }
View Code
原文地址:https://www.cnblogs.com/zaq19970105/p/10886953.html