尺取法:反复推进区间的开头和末尾,来求满足条件的最小区间的方法被称为尺取法。
一般区间有连续或者单调等特点。
例题:
求任意子序列和的绝对值与所给值相差最小的区间
求出前N项的和构成新数组,从小到大排序,再用尺取法做。。。
这题恶心,,,不想多说
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
typedef pair<int,int> P;
const int maxn = 1e5+10;
const int inf = 0x3f3f3f;
int n,m,k;
P p[maxn];
int get_sum(int &l,int &r,int &from,int &to,int &result,int k) {
if(l>=r) return INT_MIN;
int sum = p[r].first - p[l].first;
if(abs(sum-k)<abs(result-k)) {
from = min(p[l].second,p[r].second);
to = max(p[l].second,p[r].second);
result = sum;
}
return sum;
}
int main() {
while(~scanf("%d%d",&n,&m)) {
if(!n&&!m) return 0;
p[0] = make_pair(0,0);
for(int i=1; i<=n; i++) {
scanf("%d",&p[i].first);
p[i].first+=p[i-1].first;
p[i].second = i;
}
sort(p,p+n+1);
while(m--) {
scanf("%d",&k);
int result = 0x80808080;
int sum = 0x80808080;
int from;
int to;
int l=0,r=0;
for(;;) {
while(r<n&&sum<k) {
sum = get_sum(l,++r,from,to,result,k);
}
if(sum<k) break;//子序列和的绝对值最大值比k小
sum = get_sum(++l,r,from,to,result,k);
}
printf("%d %d %d\n",result,from+1,to);
}
}
}
谁能告诉我0x80808080,INT_MN,0x3f3f3f到底是些什么东西!!。。
题意:给定一个数n,求任意连续素数序列之和与n相等的序列总数。
如 53 has two representations 5 + 7 + 11 + 13 + 17 and 53(素数序列必须连续)
先素数打个表。。。
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 1e4+10;
int prime[maxn];
bool is_prime[maxn];
int p = 0;
void sieve(){
for(int i=0;i<=maxn;i++) is_prime[i] = true;
is_prime[0] = is_prime[1] = false;
for(int i=2;i<=maxn;i++){
if(is_prime[i]){
prime[p++] = i;
for(int j=2*i;j<=maxn;j+=i) is_prime[j] = false;
}
}
}
int main(){
int n;
sieve();
while(~scanf("%d",&n)){
if(!n) return 0;
int res = 0;
int s = 0,t = 0,sum = 0;
for(;;){
if(sum==n) res++;
while(t<p&&sum<n){
sum+=prime[t++];
if(sum==n) res++;
}
if(sum<n) break;
sum-=prime[s++];
}
printf("%d\n",res);
}
}
题意:给定一个数n(挺大的),求任意连续整数序列的平方的和等于n的这些序列。
如:
input 2030
output
2(表示有两个序列可以等于2030) 4 21 22 23 24(第一个数为该序列的整数个数,后面为每个整数) 3 25 26 2721^2+22^2+23^2+24^2 = 2030
题目的输出很烦,看了网上的,用到了vector。。还是不知道使用这些数据结构啊。。。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn = 1e6;
vector<pair<ll,ll> > ans;
int main() {
ll n;
while(~scanf("%lld",&n)){
ll s = 1;
ll t = 1;
ll sum = 0;
while(s*s<=n){
while(t*t<=n&&sum<n){
sum+=t*t;
t++;
}
if(sum==n){
ans.push_back(make_pair(s,t));
//printf("%lld %lld\n",s,t);
}
sum-=s*s;
s++;
}
ll num = ans.size();
printf("%lld\n",num);
for(int i=0;i<num;i++){
printf("%lld",ans[i].second-ans[i].first);
for(int j=ans[i].first;j<ans[i].second;j++){
printf(" %lld",j);
}
printf("\n");
}
}
}
总结:尺取法总的来说比较容易,只要知道了题目要用到尺取法,应该就可以做出来了,剩下的就是细节实现问题。
三个题目,大致框架都是一样。