笔试强训练习-8
加减(贪心+前缀和+滑动窗口)
无序数组求最小问题----必然排序 N*logn
枚举N^2个区间----使用滑动窗口---降为N
选出一个区间后取中点(贪心,高中的多个点到一个点求线段和最短)
判断区间使用前缀和可将 O(N)降为O(1),求出该区间到中点的最小线段和与K进行比较判断
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
LL n,k;
const int N=1e5+10;
LL a[N];LL dist[N];//前缀和
int main()
{cin>>n>>k;for(int i=1;i<=n;i++)cin>>a[i];sort(a+1,a+n+1);for(int i=1;i<=n;i++)dist[i]=dist[i-1]+a[i];LL ret=0;LL l=1;LL r=1;for(r;r<=n;r++){int mid=(l+r)/2;LL cnt=(mid-l)*a[mid]-(dist[mid-1]-dist[l-1])+dist[r]-dist[mid]-(r-mid)*a[mid];if(cnt<=k)ret=max(ret,r-l+1);else{l++;}}
// ret=max(ret,r-l);上述写法不用cout<<ret<<endl;
}
栈和排序_牛客题霸_牛客网(贪心+栈)
输出最大字典序 第一个当然是最大数n
核心:令aim尽量保持最大,判断后续输出
个人测试案例:
1 4 5 2 3
4 1 5 2 3
1 5 4 6 2 3
class Solution {
public:/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可** 栈排序* @param a int整型vector 描述入栈顺序* @return int整型vector*/vector<int> solve(vector<int>& a) {bool st[50100]={0};vector<int>ret;int n=a.size();int aim=n;stack<int>stack;for(int e:a){stack.push(e);st[e]=true;while(st[aim])aim--;while(stack.size()&&stack.top()>=aim)//一定要判断栈中是否为空,否则会多随机数{int t=stack.top();stack.pop();ret.push_back(t);}}return ret;}
};
42. 接雨水 - 力扣(LeetCode)
// class Solution {
// public:
// struct node
// {
// int cnt;int left;int right;
// };
// int trap(vector<int>& height) {
// node f[100010]; //从上到下逐层解决问题,8ms的原因是初始化和更新结构体数组
// for(int i=1;i<=100000;i++)
// {
// f[i].cnt=0;
// f[i].left=0x3f3f3f3f;
// f[i].right=0;
// }
// int tmp=0;
// for(int i=0;i<height.size();i++)
// {
// int e=height[i];
// tmp=max(tmp,e);
// f[e].cnt++;
// if(i<f[e].left)f[e].left=i;
// if(i>f[e].right)f[e].right=i;
// }// for(int i=tmp-1;i>0;i--)
// {
// f[i].cnt+=f[i+1].cnt;//f[i]统计>=i的个数
// if(f[i+1].left<f[i].left)f[i].left=f[i+1].left;
// if(f[i+1].right>f[i].right)f[i].right=f[i+1].right;
// }// int ret=0;
// for(int i=tmp;i>0;i--)//i表示高度
// {
// if(f[i].cnt>1)
// {
// int left=f[i].left,right=f[i].right;
// int len=right-left-1;
// ret+=len-(f[i].cnt-2);
// }
// }
// return ret;
// }
// };
class Solution {
public:int trap(vector<int>& height) {//从左到右解决问题(我们只需要知道当前格子左右最高高度即可计算)int n=height.size();vector<int>left(n);vector<int>right(n);right[n-1]=height[n-1];for(int i=n-2;i>=0;i--)right[i]=max(height[i],right[i+1]);left[0]=height[0];for(int i=1;i<n;i++)left[i]=max(height[i],left[i-1]);int ret=0;for(int i=0;i<n;i++){ret+=min(left[i],right[i])-height[i];}return ret;}
};
四个选项(dfs+剪枝+哈希)
#include<iostream>
using namespace std;
int cnt[5];//统计abcd的剩余次数
int m,ret;
bool same[13][13];//记录限制条件
int tree[13];//记录路径
bool check(int pos,int x)
{for(int i=1;i<pos;i++){if(same[i][pos]&&tree[i]!=x)return true;//不满足限制条件时返回}return false;
}
void dfs(int pos)
{if(pos>12){ret++;return;}for(int i=1;i<=4;i++){if(cnt[i]==0)continue;if(check(pos,i))continue;cnt[i]--;tree[pos]=i;dfs(pos+1);
// tree[pos]=0; //这个回不回溯都行,看个人习惯,因为前面tree[pos]会不断刷新,判断是也不会用pos后的信息cnt[i]++;}
}
int main()
{for(int i=1;i<=4;i++)cin>>cnt[i];cin>>m;while(m--){int x,y;cin>>x>>y;same[x][y]=same[y][x]=true;}dfs(1);cout<<ret<<endl;return 0;
}
