【尺取法】POJ3061 & POJ3320
POJ3061-Subsequence
【题目大意】
给定长度微n的数列整数及整数s。求出总和不小于s的连续子序列的长度的最小值。如果节不存在,则输出0。
【思路】
尺取法五分钟裸裸裸~刷水刷出了罪恶感:(
基本做法:设置l和r代表当前区间[l,r],若S(l,r)<s,则 r++。若S(l,r)≥s,则 l++,直至S(l,r)<s。如果当前S(l,r)<s且r=n则退出。输出最小区间长度[l,r]即可。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cmath> 5 using namespace std; 6 const int MAXN=100000+50; 7 int num[MAXN],n,s; 8 9 void solve() 10 { 11 scanf("%d%d",&n,&s); 12 for (int i=1;i<=n;i++) scanf("%d",&num[i]); 13 int l=1,r=1,sum=num[1],len=MAXN; 14 for (;;) 15 { 16 if (sum>=s) 17 { 18 len=min(len,r-l+1); 19 sum-=num[l++]; 20 } 21 else 22 { 23 if (r==n) break; 24 sum+=num[++r]; 25 } 26 } 27 if (len==MAXN) puts("0"); 28 else printf("%d\n",len); 29 } 30 31 int main() 32 { 33 int T; 34 scanf("%d",&T); 35 while (T--) solve(); 36 return 0; 37 }
POJ3320-Jessica's Reading Problem
【题目大意】
一个序列ai,其中ai可能相同。求最短的连续子序列长度,使得该子序列中包含所有的ai。
【思路】
由于ai可能非常大,先对ai进行离散化。用appear[a[i]]表示当前a[i]出现的次数。然后利用尺取法,sum表示当前区间中包含了几种不同的数,如果l右移而appear[a[l]]变为0则sum--,如果r右移而appear[a[r]]变为1则sum++。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 const int MAXN=1e6+5; 8 int appear[MAXN],p,a[MAXN],hash[MAXN],d; 9 10 void init() 11 { 12 scanf("%d",&p); 13 for (int i=1;i<=p;i++) scanf("%d",&a[i]),hash[i]=a[i]; 14 sort(hash+1,hash+p+1); 15 d=unique(hash+1,hash+p+1)-(hash+1); 16 for (int i=1;i<=p;i++) a[i]=lower_bound(hash+1,hash+d+1,a[i])-hash; 17 } 18 19 void solve() 20 { 21 memset(appear,0,sizeof(appear)); 22 appear[a[1]]=1; 23 int l=1,r=1,sum=1,ans=MAXN; 24 for (;;) 25 { 26 if (sum>=d) 27 { 28 ans=min(ans,(r-l+1)); 29 appear[a[l]]--; 30 if (!appear[a[l++]]) sum--; 31 } 32 else 33 { 34 if (r==p) break; 35 appear[a[r+1]]++; 36 if (appear[a[++r]]==1) sum++; 37 } 38 } 39 printf("%d",ans); 40 } 41 42 int main() 43 { 44 init(); 45 solve(); 46 return 0; 47 }