尺取法
找指定和的整数对
题目大意
对序列a寻找两个整数x,y使得x+y=目标值m,本题保证答案唯一。
解题思路
采用尺取法,先对a排序,然后用最大值加最小值与目标值比较,大了右端点左移,小了左端点右移,如此便可找到答案。也就是双指针操作。此外本题还可用二分法求解。
尺取法
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+5;
int n,a[N],m;
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+n+1);
// vector<array<int,2>>ans;
int i=1,j=n;
while(i<j){
int sum=a[i]+a[j];
if(sum>m)j--;
if(sum<m)i++;
if(sum==m){
// ans.push_back({a[i],a[j]});
// i++;
cout<<a[i]<<" "<<a[j]<<endl;
break;
}
}
// if(!ans.size())puts("No");
// else {
// sort(ans.begin(),ans.end(),[&](const array<int,2>&a,const array<int,2>&b){
// if(a[0]==b[0])return a[1]<b[1];
// return a[0]<b[0];
// });
// cout<<ans[0][0]<<" "<<ans[0][1]<<endl;
// }
return 0;
}
Palindromes _easy version(hdu 2029)
题目大意
判断字符串是否是回文串,即字符串翻转后与原来相同。
解题思路
双指针,一个从左向右扫描,一个从右向左扫描,当指针相遇完全匹配时是回文串。
未知的代码
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
string s;
while(n--){
cin>>s;
int l=0,r=s.size()-1;
while(s[l++]==s[r--]&&l<r);
if(l<r)puts("no");
else puts("yes");
}
return 0;
}
Subsequence (poj 3061)
题目大意
给定一个序列,求满足区间和大于或等于s的最短子序列
解题思路
使用双指针i,j均初始化指向第一个元素,移动右指针直到和大于等于目标值或到达边界,更新区间最短长度,左指针右移。最后输出最小值即可。
未知的代码
#include<bits/stdc++.h>
using namespace std;
int main(){
int t;
cin>>t;
while(t--){
int n,s;
cin>>n>>s;
vector<int>a(n);
for(auto&it:a)cin>>it;
int i=0,j=0,ans=n+1,sum=0;
while(true){ //注意条件
while(j<n&&sum<s)sum+=a[j++];
if(sum<s)break;
ans=min(ans,j-i);
sum-=a[i++];
}
cout<<((ans==n+1)?0:ans)<<endl;
}
return 0;
}
Bound Found (poj 2566)
题目大意
给定序列a,求子区间和最接近t的左右端点以及区间和。
解题思路
尺取法求最接近的前缀和区间
未知的代码
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10,inf=0x3f3f3f3f;
int n,m,k;
struct node{
int id,sum;
bool operator<(const node&e)const{
return sum<e.sum;
}
}s[N];
void solve(){
int l=0,r=1,mi=inf,x,y,ans;
while(l<=n&&r<=n&&mi!=0){
int ret=s[r].sum-s[l].sum;
if(abs(ret-k)<mi){
mi=abs(ret-k);
x=s[l].id;
y=s[r].id;
ans=ret;
}
if(ret>k)l++;
else if(ret<k)r++;
else break;
if(l==r)r++;
}
if(x>y)swap(x,y);
cout<<ans<<" "<<x+1<<" "<<y<<endl;
}
int main(){
while(cin>>n>>m&&(n||m)){
s[0].sum=s[0].id=0;
for(int i=1;i<=n;i++){
cin>>s[i].sum;
s[i].sum+=s[i-1].sum;
s[i].id=i;
}
sort(s,s+n+1);
while(m--){
cin>>k;
solve();
}
}
return 0;
}
First One(hdu 5358)
题目大意
求给定公式的区间和之和。
解题思路
暴力求解超时,考虑尺取法,由数据范围可知\(\log_2^{S(i,j)}\)不超过\(2^34\),令其为k枚举求解值为k时范围内(i+j)的和。
未知的代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
ll s[N];
int main(){
int t;
cin>>t;
while(t--){
s[0]=0;
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>s[i];
s[i]+=s[i-1];
}
ll ans=0;
for(int k=1;k<=34;k++){
ll L=1LL<<(k-1),R=(1LL<<k)-1;
if(k==1)L=0;
ll l=1,r=0;
for(int i=1;i<=n;i++){
l=max((ll)i,l);
while(s[l]-s[i-1]<L&&l<=n)l++;
r=max(r,l-1);
while(s[r+1]-s[i-1]>=L&&s[r+1]-s[i-1]<=R&&r+1<=n)r++;
if(l>r)continue;
ans+=(i*(r-l+1)+(r+l)*(r-l+1)/2)*k;
}
}
cout<<ans<<endl;
}
return 0;
}
A-B 数对(洛谷P1102)
题目大意
找指定差的数对
解题思路
二分查找
未知的代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+5;
int n,c,a[N];
signed main(){
int ans=0;
cin>>n>>c;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)ans+=(upper_bound(a+1,a+n+1,a[i]+c)-lower_bound(a+1,a+n+1,a[i]+c));
cout<<ans<<endl;
return 0;
}
Unique Snowflakes (uva 11572)
题目大意
寻找无重复元素的最长连续子序列
解题思路
使用hash_map记录上一个重复元素的下标,尚未重复记为-1,使用右指针扩展直到重复或者不可扩展,记录最大区间长,移动左指针,最后得到最大区间长度。
未知的代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
unordered_map<int,int>mp;
int last[N];
int main(){
int t,n,x;
cin>>t;
while(t--){
cin>>n;
mp.clear();
for(int i=0;i<n;i++){
cin>>x;
if(!mp.count(x))last[i]=-1;
else last[i]=mp[x];
mp[x]=i;
}
int l=0,r=0,ans=1;
while(r<n){
while(r<n&&last[r]<l)r++;
ans=max(ans,r-l);
l++;
}
cout<<ans<<endl;
}
return 0;
}
三数之和 (力扣 15)
题目大意
寻找序列中和为0的三个元素,返回全部三元组,不能重复,元素顺序不同但元素相同视为同一种。
解题思路
排序+双指针,先对元素排序,然后双指针寻找。
未知的代码
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int len=nums.size();
vector<vector<int>>res;
sort(nums.begin(),nums.end());
for(int i=0;i<len-2&&nums[i]<=0;i++)
{
if(i!=0&&nums[i]==nums[i-1]) continue;
int l=i+1,r=len-1;
while(l<r)
{
if(nums[l]+nums[i]+nums[r]>0)
r--;
else if(nums[l]+nums[i]+nums[r]<0)
l++;
else
{
res.push_back({nums[i],nums[l++],nums[r--]});
while(l<r&&nums[l]==nums[l-1]) l++;
while(l<r&&nums[r]==nums[r+1]) r--;
}
}
}
return res;
}
};

浙公网安备 33010602011771号