hdu 5289 Assignment(2015 Multi-University Training Contest 1)

Assignment

                                                              Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
                                                                                      Total Submission(s): 755    Accepted Submission(s): 373


Problem Description
Tom owns a company and he is the boss. There are n staffs which are numbered from 1 to n in this company, and every staff has a ability. Now, Tom is going to assign a special task to some staffs who were in the same group. In a group, the difference of the ability of any two staff is less than k, and their numbers are continuous. Tom want to know the number of groups like this.
 

Input
In the first line a number T indicates the number of test cases. Then for each case the first line contain 2 numbers n, k (1<=n<=100000, 0<k<=10^9),indicate the company has n persons, k means the maximum difference between abilities of staff in a group is less than k. The second line contains n integers:a[1],a[2],…,a[n](0<=a[i]<=10^9),indicate the i-th staff’s ability.
 

Output
For each test,output the number of groups.
 

Sample Input
2 4 2 3 1 2 4 10 5 0 3 4 5 2 1 6 7 8 9
 

Sample Output
5 28
Hint
First Sample, the satisfied groups include:[1,1]、[2,2]、[3,3]、[4,4] 、[2,3]
 

Author
FZUACM
 

Source
 


題目大意:
    
        求一段連續區間的最大值與最小值的差小於k的個數。

解題思路:
       
       這題解題方法很多,線段樹,二分+rmq,單調隊列,multiset,我們隊比賽的時候用multiset過的,後來看題解單

調隊列可以過,單調隊列還不會,就去網上找了些資料,用單調隊列做的。

        單調遞減隊列是這麼一個隊列,它的頭元素一直是隊列當中的最大值,而且隊列中的值是按照遞減的順序排列的。我們可以從隊列的末尾插入一個元素,可以從隊列的兩端刪除元素。

1.首先看插入元素:爲了保證隊列的遞減性,我們在插入元素v的時候,要將隊尾的元素和v比較,如果隊尾的元素不大於v,則刪除隊尾的元素,然後繼續將新的隊尾的元素與v比較,直到隊尾的元素大於v,這個時候我們纔將v插入到隊尾。

2.隊尾的刪除剛剛已經說了,那麼隊首的元素什麼時候刪除呢?由於我們只需要保存i的前k-1個元素中的最大值,所以當隊首的元素的索引或下標小於i-k+1的時候,就說明隊首的元素對於求f(i)已經沒有意義了,因爲它已經不在窗裏面了。所以當index[隊首元素]<i-k+1時,將隊首元素刪除。


    於是這題可以用兩個單調隊列來做,一個維護最大值,一個維護最小值,當不滿足條件時,更改在序列前面的那個

最值。



代碼(單調隊列)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int inf=0x7fffffff;
const int maxn=100000+100;
int l[maxn];
int r[maxn];
struct node
{
    int x;
    int cur;
}a[maxn],b[maxn],p;

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,k;
        scanf("%d%d",&n,&k);
        int cur=1;
        scanf("%d",&a[1].x);
        a[1].cur=b[1].cur=1;
        b[1].x=a[1].x;
        int front1=1,front2=1;
        int cur1=1,cur2=1;
        long long ans=1;
        for(int i=2;i<=n;i++)
        {
            scanf("%d",&p.x);
            p.cur=i;
            for(int j=cur1;j>=front1;j--)//維護最大值
            {
                if(p.x<=a[j].x)
                {
                    a[j+1].x=p.x;
                    a[j+1].cur=p.cur;
                    cur1=j+1;
                    break;
                }
                if(j==front1)
                {
                    a[front1].x=p.x;
                    a[front1].cur=p.cur;
                    cur1=front1;
                    break;
                }
            }
            for(int j=cur2;j>=front2;j--)//維護最小值
            {
                if(p.x>=b[j].x)
                {
                    b[j+1].x=p.x;
                    b[j+1].cur=p.cur;
                    cur2=j+1;
                    break;
                }
                if(j==front2)
                {
                    b[front2].x=p.x;
                    b[front2].cur=p.cur;
                    cur2=front2;
                    break;
                }
            }
            while(a[front1].x-b[front2].x>=k)//不滿足條件
            {
                if(a[front1].cur<b[front2].cur)//刪除最大值
                {
                    cur=a[front1].cur+1;//區間長度在刪除前向後移1位
                    front1++;
                }
                else
                {
                    cur=b[front2].cur+1;
                    front2++;
                }
            }
            ans=ans+(i-cur+1);
        }
        printf("%I64d\n",ans);
    }
    return 0;
}


代碼(multiset)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;

int n,k,num[100010];

int main()
{
//    freopen("D:\\in.txt","r",stdin);
    int T,i,j;
    cin>>T;
    while(T--)
    {
        cin>>n>>k;
        multiset<int> ss;
        multiset<int>::iterator it;
        multiset<int>::reverse_iterator itt;
        for(i=0;i<n;i++)
            scanf("%d",&num[i]);
        int st=0,ed=0;
        int mi=num[0],ma=num[0];
        long long ans=0;
        while(st<n)
        {
            while(ed<n)
            {
                if(num[ed]<=ma&&num[ed]>=mi)
                {
                    ss.insert(num[ed++]);
                    continue;
                }
                if(num[ed]<mi)
                {
                    if(ma-num[ed]<k)
                    {
                        mi=num[ed];
                        ss.insert(num[ed++]);
                        continue;
                    }
                    else
                    {
                        ed--;
                        break;
                    }
                }
                if(num[ed]>ma)
                {
                    if(num[ed]-mi<k)
                    {
                        ma=num[ed];
                        ss.insert(num[ed++]);
                        continue;
                    }
                    else
                    {
                        ed--;
                        break;
                    }
                }
            }
            if(ed==n) ed--;
            ans+=ed-st+1;
            it=ss.find(num[st]);
            ss.erase(it);
            if(!ss.empty())
            {
                it=ss.begin();
                mi=*it;
                itt=ss.rbegin();
                ma=*itt;
            }
            else
            {
                mi=ma=num[st+1];
            }
            st++;
            if(st>ed)
                ed=st;
            else
                ed++;
        }
        cout<<ans<<endl;
    }
}



發佈了249 篇原創文章 · 獲贊 7 · 訪問量 56萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章