做题小结2

第一个题目

这题是真麻烦 调起来
不过还好写的时候思路清晰 明白了要分段做 碰到0或者到头了 就需要返回 然后就是记录一个答案
需要求出前面的头指针此时下标 然后要明白返回的l r 之间要记录是二者的距离 这样方便求二者的下标 别的就没啥了 思路正确 做起来还是蛮快的 就是调的难受

node check() {
	int l = 0;	int r = 0;
	node  x;	int num = 0;	int  two = 0;
	int temp = 0;	int temptemp = 0;
	for (int i = 1; i <= step; i++) {
		if (b[i] < 0) {
			if (!l)l = i;
			r = i;
			num++;
		}
	}
	if (l == r && num == 1) {
		for (int i = l + 1; i <= step; i++)
			if (b[i] == 2)two++;了
		for (int i = 1; i <= l - 1; i++)
			if (b[i] == 2)temp++;
		if (temp > two) {
			x.ans = temp;
			x.l = 1;
			x.r = l - 1;			
		}
		else {
			x.ans = two;
			x.l = l + 1;
			x.r = step;
		}
		return x;
	} 
	else if (num % 2) {
		for (int i = 1; i <= l - 1; i++)     if (abs(b[i]) == 2)temp++;
		for (int i = r + 1; i <= step; i++)	 if (abs(b[i]) == 2)temptemp++;
		for (int i = l + 1; i <= r - 1; i++)	if (abs(b[i]) == 2)two++;
		int g = 0;
		g = two + temp + ((b[l] == -2) ? 1 : 0);
		int gg = 0;
		gg = two + temptemp + ((b[r] == -2) ? 1 : 0);
		if (g > gg) {
			x.ans = g;
			x.l = 1;
			x.r = r - 1;
		} else {
			x.ans = gg;
			x.l = l + 1;
			x.r = step;
		}
		return x;
	}
	else {
		for (int i = 1; i <= step; i++)
			if (b[i] == 2 || b[i] == -2)two++;
		x.ans = two;
		x.l = 1;
		x.r = step;
		return x;
	}
}

第二个题目

这题一开始想麻烦了 开成3n*3n 后面才意识到左右循环 算一次就行了 反正答案是一样的 你想想左移1位不就是右移动n-1位吗 可以一次性算两个答案 那么上下也是同理

然后记录答案我想了半天 对角线如何o1求 后面还是看了题解 才明白人家用的前缀和 用最没有逻辑思路i-1 j-1 去记录对角线 而我还看了八皇后这些 去优化 最终还是没弄出来 。。。。别的就没啥了

#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
const int range = 6e3 + 5;
int n;
char  a[range][range];
int sum[range][range];
int num=0;
void st() {
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
		{
		    cin >> a[i][j];	
			if(a[i][j]=='1')num++;
		}
	for (int i = 1; i <=  n; i++) {
		for (int j =  n + 1; j <= 2 * n; j++)
			a[i][j] = a[i][j - n];
	}
	for (int i = n + 1; i <= 2 * n; i++) {
		for (int j = 1; j <= n; j++)a[i][j] = a[i - n][j];
		for (int j = n + 1; j <= 2 * n; j++)a[i][j] = a[i][j - n];
	}
}
//会有很多浪费 但懒得优化了 如果跑不过 我就优化下
//我是笨比 一开始开的3n 越做越不对劲 于是2n 因为左移右移方案一样的
//int check(int x, int y, int xx, int yy) {
//	int num = 0;
//	for (int i = x; i <= xx; i++) {
//		for (int j = y; j <= yy; j++) {
//			if (i == j) {
//				if (a[i][j] == 0)num++;
//			} else {
//				if (a[i][j] == 1)num++;
//			}
//		}
//	}	ans = min(check(i - n + 1, j - n + 1, i, j), ans);
//	return num;
//}
void solve() {
	cin >> n;
	num=0;
	st();
//	for(int i=1;i<=2*n;i++)
//	{
//		for(int j=1;j<=2*n;j++)
//		{
//			cout<<a[i][j]<<" ";
//		}
//		cout<<endl;
//	}
//	cout<<endl;
	
//	for (int i = 1; i <= n * 2; i++) {
//		for (int j = 1; j <= n * 2; j++) {
//			sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + a[i][j];
//		}
//	}复习二位前缀和 与二维前缀m类型
	int ans = 1e9;
	for (int i = 1; i <= 2 * n; i++) {
		for (int j = 1; j <= 2 * n; j++) {
			sum[i][j]=sum[i-1][j-1]+(a[i][j]-'0');
		}
	}
//	for(int i=1;i<=2*n;i++)
//	{
//		for(int j=1;j<=2*n;j++)
//		{
//			cout<<sum[i][j]<<" ";
//		}
//		cout<<endl;
//	}
//	cout<<endl;
	//假设num为所有的1的值 sum为对角线为1的值 
	//则代价为(n-sum)+num-sum  n-sum 对角线0 后面的是遗落在外面的1
	//求对角线 我想了半天优化对角线方法 都不合适 属实是舍本逐末了
	//边界就很好算了 区间dp一样求一个len  
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{	
		ans=min(ans,(n+num)-2*(sum[i+n-1][j+n-1]-sum[i-1][j-1]));	
			//别忘了减之前的!
		}
	}
	cout << ans << endl;
}

第三个

这个题目 cf的翻译简直依托 看lg的明白才明白 这个+-要明白何时转化 两个相邻的-转化+
可能你会在想相邻怎么弄 其实画几个图就能明白 如果一段串出现负数 那一定会有相邻的负号 +--这种就可以换 咱们知道

+---这种才能抵消 打个表就发现负数是3的倍数才行 于是就ac了

#include<bits/stdc++.h>
#define int long long 
#define endl '\n'
using namespace std;
const int range=2e5+10;
int n;
string s;
int sum[range]; 
void solve()
{
	cin>>n;
	cin>>s;
	s=' '+s;
	for(int i=1;i<=n;i++)
	{
		if(s[i]=='+')sum[i]=sum[i-1]+1;
		else sum[i]=sum[i-1]-1;
	}
	int num=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=i;j<=n;j++)
		{
			if(i==j)continue;
			if(sum[j]-sum[i-1]>0)continue;
			else if(sum[j]-sum[i-1]==0)num++;
			else {
				if(abs(sum[j]-sum[i-1])%3==0)num++;
			}
			// cout<<sum[j]-sum[i-1]<<" "<<i<<" "<<j<<endl;
		}
	}
	cout<<num<<endl;
	//-+---
	//1 3 
	// 1 5 
	// 2 4 
	//3 
//	if(sum[j]-sum[i-1]==0)num++;
//			else {
//				if(abs(sum[j]-sum[i-1])%4==0)num++;
//			}
}

} 

第四个

这个已经在专栏讲过了 就不说了

第五个

这个题比较有意思 我个人认为没有二分做的必要 我做这个题
目 我写下我当时的顾虑

第一个

对于要更改的那一段 有两个元素 我想 那可能把前者往
后移动 或者前移,当如后者元素也是同理 我当时就想 不会这么麻烦吧?还是懒 看到1900 不敢想下去了

第二个

我没有贪心的思想 竟然没有想到第一反应应该去找最小的那一段 先找出来 而是考虑二分 返回num<=1 这种写法,也怪自己瞟了标签 看到二分 跟二分没关系 这是贪心题 二分做只会麻烦

第三个

没有想到改动的后我们如何放置 我们应该贪心思考到 应该放到改动后队列中 间距最大的二者之间 或者放最后试试 这里默认0也有不过不是比赛

第四个
我当时想了半天改两个 到底改哪个 其实想那么多干什么 这肯定可以枚举啊

第六个
题目

这个题 我没做出来
自己总结下思路吧 对于一个数一直/2 知道<n为止 如果此时已经存在 继续除下去 很明显这种思路是对的

posted @ 2025-04-16 19:46  LteShuai  阅读(10)  评论(0)    收藏  举报