(K. Keylogger)[https://codeforces.com/gym/103185/problem/K]

[[TOC]] 目录

tag:

  • cf分段2100
  • 动态规划,二分查找,计数,前缀差分

题意:

给定矩阵,对于矩阵第i行,每行都是上升子序列。 给定序列,求矩阵转移找满足序列的个数。

题解:

先寻找满足区间范围的数字,用的是两次二分,这样可以快速固定区间。

然后对于区间内静态查询动态修改,可以考虑使用前缀差分来加速。

最后就是滚动dp压缩空间,可以加快访问速度。

代码:


#include<bits/stdc++.h>
using namespace std;
const int  maxn = 2e3 + 7;
#define ll long long
ll x[maxn][maxn];
ll dp[2][maxn];
ll y[20000];
const int mod = 1e9 + 7;
int main() {
	ios::sync_with_stdio(0);
	ll n, k;
	cin >> n>>k;
	for (int i = 1; i <= n; i++) 
		for (int j = 1; j <= n; j++) 
			cin >> x[i][j];
	int m;
	cin >> m;
	for (int j = 1; j < m; j++) 
		cin >> y[j];
	
	for (int i = 1; i <= n; i++) {
		dp[0][i] = 1;
	}
	for (int j = 1; j < m; j++) {
		//vector<int>ve(n + 2);
		int t = j & 1;
		for (int i = 1; i <= n; i++) {
			dp[t][i] = 0;
		}

		for (int i = 1; i <= n; i++) {

			auto kkk = lower_bound(x[i] + 1, x[i] + n + 1, y[j] - k) - x[i];
			auto kk = upper_bound(x[i] + 1, x[i] + n + 1, y[j] + k) - x[i];
			
			dp[t][kkk] = (dp[t][kkk] + dp[t ^ 1][i]) % mod ;
			dp[t][kk] = (dp[t][kk] - dp[t ^ 1][i] + mod) % mod;

		}
		for (int i = 1; i <= n; i++) {
			dp[t][i] = (dp[t][i] + dp[t][i - 1]) % mod;
		}
	}
	ll ans = 0;
	for (int i = 1; i <= n; i++) {
		ans += dp[(m - 1) & 1][i];
		ans %= mod;
	}
	cout << ans << "\n";

	
}