随笔 - 216,  文章 - 0,  评论 - 17,  阅读 - 25574

比赛链接:

https://codeforces.com/contest/1720

D. Xor-Subsequence

题意:

长为 n 的序列,找到最长的子序列 b,设序列 b 长为 m,使得 abpbp+1<abp+1bp(0<=p<m1),序列下标都从 0 开始。

思路:

easyversion

转化一下关系 a[j]i<a[i]j
考虑简单的 dp。在满足上述条件下,dp[i]=maxj=0i(dp[i]+1)。会超时。
因为 ai<=200 所以意味着 i 的变化不会超过 8 位,即 ai256<=ai200<=ai+256
所以优化一下,j 不用从 0 开始,从 i256 开始就行。

#include <bits/stdc++.h>
using namespace std;
#define LL long long
void solve(){
	int n;
	cin >> n;
	vector <LL> a(n), dp(n, 1);
	for (int i = 0; i < n; i ++ ){
		cin >> a[i];
		for (int j = max(0, i - 256); j < i; j ++ ){
			if ((a[j] ^ i) < (a[i] ^ j)){
				dp[i] = max(dp[i], dp[j] + 1);
			}
		}
	}
	cout << *max_element(dp.begin(), dp.end()) << "\n";
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	int T;
	cin >> T;
	while(T -- ){
		solve();
	}
	return 0;
}

ai 的范围扩大到 1e9 的时候,上述方法就不行了。
a[j]i<a[i]j,意味着在二进制的状态下,前 k 位是相同的,即对于前 k 位来说,a[j]i=a[i]j,两边都乘上 ij,得到 a[j]j=a[i]i
对于第 k+1 位,a[j]i<a[i]j,即 a[i]j=1a[j]i=0
得到 a[i]!=j,a[j]=i,那么 a[i]i=!a[j]j
考虑将 a[j]j 插入字典树中,插入的时候,因为 a[i]!=j,所以每一位将 j 都要记录下来,更新对应位置的最大值。
查询的时候,要导入 a[i],找到 a[i]i=!a[j]ja[i]!=j 的最大值。

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 3e5 + 10;
struct Trie{
	LL ch[N * 30][2], f[N * 30][2], idx = 0;
	void reset(){
		for (int i = 0; i <= idx; i ++ ){
			for (int j = 0; j < 2; j ++ ){
				ch[i][j] = f[i][j] = 0;
			}
		}
		idx = 0;
	}
	void insert(LL x, LL t, LL mx){
		LL u = 0;
		for (int i = 30; ~ i; i -- ){
			LL &v = ch[u][x >> i & 1];
			if (!v) v = ++ idx;
			u = v;
			f[u][t >> i & 1] = max(f[u][t >> i & 1], mx);
		}
	}
	LL query(LL x, LL id){
		LL u = 0, res = 1;
		for (int i = 30; ~ i; i -- ){
			LL v = x >> i & 1;
			res = max(res, f[ch[u][!v]][!(id >> i & 1)] + 1);
			if (!ch[u][v]) break;
			u = ch[u][v];
		}
		return res;
	}
}trie;
void solve(){
	int n;
	cin >> n;
	vector <LL> a(n);
	for (int i = 0; i < n; i ++ )
		cin >> a[i];
	vector <LL> dp(n);
	for (int i = 0; i < n; i ++ ){
		dp[i] = trie.query(a[i] ^ i, a[i]);
		trie.insert(a[i] ^ i, i, dp[i]);
	}
	cout << *max_element(dp.begin(), dp.end()) << "\n";
	trie.reset();
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	int T;
	cin >> T;
	while(T -- ){
		solve();
	}
	return 0;
}

E. Misha and Paintings

题意:

nn 的矩阵,每个位置有一个数字 ai,j,每次可以选择一个正方形将其中的元素全部改成 k1knn,问最少多少次操作可以使得矩阵中的不同数字的值等于 t

思路:

统计矩阵中不同数字的个数 cnt,如果 cntt,那么最少 tcnt 次。
否则答案可以通过构造的操作,至多为二。
在矩阵中选择一个矩阵,将其改为某个元素,此操作可以让整个矩阵中不同元素的数量 t,如果为 t 或者 t1,可以根据填充的不同数字使得得到答案 t
如果不是,记该矩阵右下角坐标为 x,y ,选择 x+1,y+1 作为第二次操作的矩阵的右下角,往左上扩张,此操作可以让整体矩阵不同元素的数量减少 0 或 1 或 2,由此至多为 2。
矩阵覆盖何时可以让某个值消失,需要记录该元素的横纵坐标的最大最小值,通过二维前缀和/差分去进行快速统计。

代码:

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	int n, k;
	cin >> n >> k;
	vector<vector<int>> a(n + 1, vector<int>(n + 1));
	vector<bool> has(n * n + 1);
	int cnt = 0;
	for (int i = 1; i <= n; i ++ ){
		for (int j = 1; j <= n; j ++ ){
			cin >> a[i][j];
			if (!has[a[i][j]]){
				cnt ++ ;
				has[a[i][j]] = true;
			}
		}
	}
	if (cnt <= k){
		cout << k - cnt << "\n";
		return 0;
	}
	
	vector<int> xmin(n * n + 1, n + 1), ymin(n * n + 1, n + 1), xmax(n * n + 1, 0), ymax(n * n + 1, 0);
	for (int i = 1; i <= n; i ++ ){
		for (int j = 1; j <= n; j ++ ){
			xmin[a[i][j]] = min(xmin[a[i][j]], i);
			ymin[a[i][j]] = min(ymin[a[i][j]], j);
			xmax[a[i][j]] = max(xmax[a[i][j]], i);
			ymax[a[i][j]] = max(ymax[a[i][j]], j);
		}
	}
	for (int len = 1; len < n; len ++ ){
		vector<vector<int>> sum(n + 2, vector<int>(n + 2));
		for (int i = 1; i <= n * n; i ++ ){
			if (!has[i] || xmax[i] - xmin[i] + 1 > len || ymax[i] - ymin[i] + 1 > len) continue;
			int x = max(1, xmax[i] - len + 1);
			int y = max(1, ymax[i] - len + 1);
			sum[x][y] ++ ;
			sum[x][ymin[i] + 1] -- ;
			sum[xmin[i] + 1][y] -- ;
			sum[xmin[i] + 1][ymin[i] + 1] ++ ;
		}
		for (int i = 1; i <= n; i ++ ){
			for (int j = 1; j <= n; j ++ ){
				sum[i][j] += sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];
				if (cnt - sum[i][j] == k || cnt - sum[i][j] == k - 1){
					cout << "1\n";
					return 0;
				}
			}
		}
	}
	cout << "2\n";
	return 0;
}
posted on   Hamine  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
< 2025年3月 >
23 24 25 26 27 28 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 1 2 3 4 5

点击右上角即可分享
微信分享提示