做题小结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为止 如果此时已经存在 继续除下去 很明显这种思路是对的

浙公网安备 33010602011771号