要求动态维护一个01矩阵,支持:1.从顶部删除一行2.从尾部添加一行3.询问当前顶部某列到尾部某列的合法路径数其中合法路径数定义为,每次只能从[i,j]−>[i,j−1]or[i,j]or[i,j+1],且要求两点同为0或1矩阵列数=20,操作数=3e5
做法
显然路径数可以通过简单dp求得,从尾部添加一行也很简单,可以O(col)求得,但是删除操作很麻烦,必须全部重算.此时就有一个trick了,当要求的是双端队列操作,但是只有添加可以快速做,那就可以用两个对顶栈来操作.开口向上的为s1,开口向下的为s2尾部添加就让s2的栈指针++,并且O(col)更新顶部删除就让s1的栈指针–,注意如果s1的栈指针为0,就把s2的所有值搬到s1,此时就相当于给s1添加,s2删除.列数很少,我们直接保存所有可能的$n^2$个答案,然后每次修改也都是$n^2$的.询问的话, $n^2$处理下对顶处部分答案的合并即可.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
| #include <bits/stdc++.h> #define mp make_pair #define pb push_back #define sz(x) (int)x.size() #define all(x) begin(x), end(x) #define fi first #define se second #define debug(x) cerr << #x << " " << x << '\n' using namespace std; using ll = long long; using pii = pair<int,int>; using pli = pair<ll,int>; const int INF = 0x3f3f3f3f, N = 3e5 + 5, M = 25; const ll LINF = 1e18 + 5; constexpr int mod = 1e9 + 7; int n, q, sta[2]; int dp[2][N][M][M]; string p[2][N]; void upd(int idx) { int x = sta[idx]; if(x==1) { for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) dp[idx][x][i][j] = (i==j); } else { for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) { dp[idx][x][i][j] = 0; for(int k=j-1; k<=j+1; k++) { if(k<1||k>n||p[idx][x-1][k-1]!=p[idx][x][j-1]) continue; dp[idx][x][i][j] += dp[idx][x-1][i][k]; if(dp[idx][x][i][j]>=mod) dp[idx][x][i][j] -= mod; } } } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n >> q; while(q--) { string op; cin >> op; if(op[0]=='a') { cin >> p[1][++sta[1]]; upd(1); } else if(op[0]=='r') { if(sta[0]==0) { while(sta[1]) { p[0][++sta[0]] = p[1][sta[1]--]; upd(0); } } sta[0]--; } else { int a, b; cin >> a >> b; if(sta[0]==0) cout << dp[1][sta[1]][a][b] << '\n'; else if(sta[1]==0) cout << dp[0][sta[0]][b][a] << '\n'; else { int ans = 0; for(int i=1; i<=n; i++) for(int j=i-1; j<=i+1; j++) { if(j<1||j>n||p[0][1][i-1]!=p[1][1][j-1]) continue; ans += 1ll*dp[0][sta[0]][i][a]*dp[1][sta[1]][j][b]%mod; if(ans>=mod) ans -= mod; } cout << ans << '\n'; } } } return 0; }
|