大数以相对大小为key,映射到下标为很小的位置,依靠相对位置进行维护(当且仅当数据个数较小时可以处理)
手段:以相对位置为依据进行哈希
a [ M ] a[M] a[M],对离散化的大数进行各种操作
a l l s [ M ] alls[M] alls[M] 存放本来的所有大数,需要找到大数对应的小数坐标的时候就在这个数组里二分他的相对位置
读入所有的大数,排序去重
sort(alls.begin(),alls.end());
alls.erase(unique(alls.begin(),alls.end()),alls.end());
int find (int x)
{
int l = 0, r = alls.size() - 1;
while (l < r)
{
int mid = (l + r) >> 1;
if (alls[mid] >= x) r = mid;
else l = mid + 1;
}
return r+1;
}
题目:把n个区间中所有有交集的区间合并
思路::考虑贪心
void merge()
{
int xx,yy;
cin>>n;
for (int i = 1; i <= n; i ++ )cin>>xx>>yy,alls.push_back({xx,yy});
sort(alls.begin(),alls.end());
st=alls[0].x;
ed=alls[0].y;
for (int i = 1; i < n; i ++ )
{
pii op=alls[i];
if(op.x<=st&&op.y>ed)ed=op.y;
if(op.x>ed)
{
add.push_back({st,ed});
st=op.x;
ed=op.y;
}
}
add.push_back({st,ed});
cout << add.size();
}
用途:判环,各种系列匹配题目,kmp,优化各种算法
要求:序列单调性,这是一种和二分一样的性质,可以从二分上迁移
结构:
for(int i=0,j=0;i<=n;i++)
{
while (check(i,j))j++;
//每道题目的具体逻辑
}
时间复杂度: O ( 2 n ) O(2 n) O(2n)相当感人!!
给定一个长度为 n n n 的整数序列,请找出最长的不包含重复的数的连续区间,输出它的长度。
思路:
int s[M],a[M];
int work(){
for(int i=0,j=0;i<n;i++)
{
cin>>a[i];
s[a[i]]++;
while(s[a[i]]>1)s[a[j++]]--;
ans=max(ans,i-j+1);
}
return ans;
}
求证数组 a a a 是否是 b b b 的子序列
思路:
bool work()
{
for(int i=0,j=0;i<n;i++)
{
while (a[i]!=b[j]&&j<m-1)j++;
if(j==m-1&&i<n-1)return 0;
j++;
}
return 1;
}
前提是保序,否则失去单调性无法维护了
思考过程就略了吧
pii work()
{
for(int i=0,j=m-1;i<n;i++)
{
while (a[i]+b[j]>x)j--;
if(x==a[i]+b[j])return make_pair(i,j);
}
}