双指针扫描 / 尺取法

来源:互联网 发布:最新熊片数据库 编辑:程序博客网 时间:2024/04/30 01:41

例①:
给定长度为n的整数数列以及整数S,求出总和不小于(>=)S的连续子串的长度的最小值,如果解不存在,输出0
分析:



代码:

int main(){    int n, s, a[10001];    //输入    cin >> n >> s;    for(int i = 1; i <= n; ++i)        cin >> a[i];    int l = 1, sum = 0, ans = inf;//初始化    for(int i = 1; i <= n; ++i)//线性扫描    {        sum += a[i];//将a[i]加入sum        if(sum >= s)//如果发现sum大于等于了s        {            while(sum >= s)//将sum减为小于s            {                sum -= a[l];                l++;//移动左指针,右指针是i            }        ans = min(ans,i - l + 1 + 1);//i - l + 1为区间[l,i]中元素的个数,由于使得sum小于了s,所以还要加1(相当于把不该删掉的元素加回来)        }    }    cout << ans << endl;//打印    return 0;}

例②:

  • 小明喜欢收集卡片,他要去商店购买新到的卡片。商店出售的卡片有N张,是连续的,小明只能购买连续的一段,这一串卡片共有M种,每种卡片都有一个价格,小明拿的钱数为V,他想知道如何用花最少的钱来集齐所有种类的卡片。
  • N<=1000000 ,M<=2000 ,Ti<=2000 , V<=10^9
  • 输入第1行 三个正整数 N,M,V,第2行共M个正整数,第i个数Ti表示第i种卡片的价格,第3行 N个正整数,表示第i个卡片是哪一类。
  • 输出小明还剩多少钱

代码:

int cnt[2010],kind[1000010];//cnt[i]记录类型为i的卡片买的数量,kind[i]表示第i个卡片是哪一类,一定要将kind定义成全局变量int main(){    int n, m, v, t[2010];    //输入    cin >> n >> m >> v;    for(int i = 1; i <= m; ++i)        cin >> t[i];    for(int i = 1; i <= n; ++i)        scanf("%d",&kind[i]);    int SumOfKind = 0,sum = 0,l = 1,ans = inf;//初始化,SumOfKind记录已买到卡片的种类数,sum记录所花金钱,l为左指针,ans为答案,每次取较小值    for(int i = 1; i <= n; ++i)//线性扫描    {        if(cnt[kind[i]] == 0)//如果第i张卡片所属种类还没有买过            SumOfKind++;//买下来,种类数+1        cnt[kind[i]]++;//张数+1        sum += t[kind[i]];//花费增加        while(cnt[kind[l]] > 1)//当发现左指针所指的卡片所属种类已经购买了多张        {            sum -= t[kind[l]];//减去花费            cnt[kind[l]]--;//张数-1            l++;//左指针+1        }        if(SumOfKind == m)//如果集齐了所有种类的卡片            ans = min(ans,sum);//更新答案    }    cout << v - ans << endl;    return 0;}
原创粉丝点击