适用情况:当搜索区间具有伸缩的特性,用双指针维护
由于是升序序列,j指针指向右端,i指针指向左端,sum维护这段数的和
#include <bits/stdc++.h>
using namespace std;
int main()
{
int m;
cin>>m;
int sum=1;
int i=1;
int j=1;
while(j<=m/2)
{
if(sum<m)
{
j++;
sum+=j;
}
if(sum>=m)
{
sum-=i;
i++;
}
if(sum==m)
cout<<i<<" "<<j<<""<<endl;
}
return 0;
}
题目条件为非严格单调递增序列,可能有重复的数字出现,i和j所维护的区间内都是相同的数字,这些数减去a[k]为x,则方案数是j-i
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL a[100000];
int main()
{
LL n,x;
cin>>n>>x;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
LL i=1;
LL j=1;
LL ans=0;
for(int k=1;k<=n;k++)
{
while(i<=n&&a[i]-a[k]<x)
i++;
while(j<=n&&a[j]-a[k]<=x)
j++;
ans+=j-i;
}
cout<<ans<<endl;
return 0;
}
思路是如果当前区间内有画家遗漏,一直更新右指针j直到每个画家至少有一幅画在区间里,然后更新左指针i删除画,如果删除a[i]后有画家没画了,再更新右指针
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int a[1000005]; //a[i]表示第i幅画的画家编号
int b[2005]; //b[j]表示当前区间中画家j的图画数
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
int l=1;
int r=1;
int mini=1000005; //记录区间长度
b[a[1]]=1;
int num=1; //记录当前区间有多少位画家
int ansl; //记录合法区间的左端点
int ansr; //记录合法区间的右端点
while(r<=n)
{
if(num<m)
{
r++;
b[a[r]]++;
if(b[a[r]]==1)
num++;
}
if(num==m)
{
if(r+1-l<mini)
{
mini=r+1-l;
ansl=l;
ansr=r;
}
b[a[l]]--;
if(b[a[l]]==0)
num--;
l++;
}
}
cout<<ansl<<" "<<ansr<<endl;
return 0;
}
思路与上一题基本类似,不过换了map存储
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
string text[100005];
map<string,int> word; //word[x]=1表示单词x要背
map<string,int> cnt; //cnt[x]表示单词出现的次数
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int sum=0; //sum表示目前有几类目标单词
int len=0; //记录目标单词最多的区间的最短长度
int n,m;
cin>>n;
for(int i=1;i<=n;i++)
{
string x;
cin>>x;
word[x]=1;
}
cin>>m;
for(int i=1,j=1;j<=m;j++)
{
cin>>text[j];
if(word[text[j]])
cnt[text[j]]++;
if(cnt[text[j]]==1)
{
sum++;
len=j-i+1;
}
while(i<=j)
{
if(cnt[text[i]]==1)
break;
if(cnt[text[i]]>1)
{
cnt[text[i]]--;
i++;
}
if(word[text[i]]!=1)
i++;
}
len=min(len,j-i+1);
}
cout<<sum<<endl;
cout<<len<<endl;
return 0;
}
i指针控制区间左端,用j指针试错来扩展右端,出错时j指向合法区间右端点,则ans+=j-i+1。第一次写时没注意到^的优先级小于==,下次注意。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=2e5+5;
int a[N];
int main()
{
int n;
cin>>n;
LL sum1=0; //算数和
LL sum2=0; //异或和
LL ans=0;
for(int i=1;i<=n;i++)
cin>>a[i];
int i=1;
int j=0;
while(i<=n)
{
while(j+1<=n&&sum1+a[j+1]==(sum2^a[j+1]))
{
j++;
sum1+=a[j];
sum2^=a[j];
}
ans+=j-i+1;
sum1-=a[i];
sum2^=a[i];
i++;
}
cout<<ans<<endl;
return 0;
}
部分代码思路参考b站up主:董晓算法