1. 程式人生 > >Problem C: 多執行緒 解題報告

Problem C: 多執行緒 解題報告

Problem C: 多執行緒

Description

多執行緒是一種常見的加速手段,利用多個執行緒同時處理不同的任務可以一定程度上減少總耗時,達到提高效率的目的。然而,多個執行緒間的執行順序是完全不可控的,這常常會導致一些意料之外的問題。

一個簡單的例子,如果三個執行緒分別輸出A,B,C, 你同時啟動這三個執行緒,最終的輸出可能是ACB也可能是CBA等等。更極端的例子,如果兩個執行緒分別輸出AB和ab,你甚至可能看到類似AaBb和aABb的輸出。

當你拿到一串輸出而他們屬於多個執行緒的時候,反推出每個執行緒的輸出是一件非常麻煩的事情(甚至有時候完全不可能),很不幸,接下來你的任務就是這樣一件麻煩事。

【題意描述】

現在有兩個執行緒同時在輸出數列,執行緒A輸出一個單調遞增數列,而執行緒B輸出一個單調遞減數列。

距離來說,如果執行緒A輸出的是11,33,55,而執行緒B輸出的是44,22,那麼你可能看到以下的結果:

11 33 55 44 22

44 22 11 33 55

11 44 33 22 55

......

我們假設單個數的輸出是不會被打斷的(這個性質往往稱為“原子操作”),你不必擔心兩個數被同時輸出從而混合成一個新的數。換言之,如果A輸出x個數而B輸出y個數,你最後一定會得到這x+y個數,只是順序不確定。

特別的,某個執行緒的輸出可能是空,你需要考慮到這一點。

現在你得到了最終的輸出,你需要反推出哪些數來自於執行緒A而哪些數來自於執行緒B。由於可能有多種情況,我們只要求你輸出方案數對1000000007取模的結果。

Input

第一行一個正整數T,表示測試資料組數。

接下來T行,每行描述一組測試資料:

第一個整數n,表示最終的輸出包含n個整數

接下來n個整數ci,表示最終的輸出。

這些整數兩兩不同。

Output

共T行,每行一個整數,表示可能的情況數。
特別的,如果無解,你需要輸出一個0。

HINT

對於100%的資料,1<=T<=10。
對於20%的資料,n<=20。
對於50%的資料,n<=1000。
對於80%的資料,n<=50000。
對於100%的資料,0<=n<=500000。
對於100%的資料,ci的絕對值不超過2000000000,且同一組資料內ci兩兩不同。


正解在我這種菜的人來說簡直不可做,我大概也說不清楚...

談一下想法好了。這種型別的題本質是在挖掘狀態中間的特殊性,就像莫名其妙看出這個是凸的一樣,這個題可以發現一些狀態在區間上連續,一些轉移在值域上單調,然後通過勢能均攤分析,可以得到非常玄妙的複雜度。這種題現在我反正是做不來的,就慢慢見識見識吧。


Code:

#include <cstdio>
const int N=5e5+10;
const int inf=0x7fffffff,mod=1e9+7;
struct node
{
    int val,cnt;
    node(){}
    node(int val,int cnt){this->val=val,this->cnt=cnt;}
}s0[N],s1[N];
int T,n,a[N],tot0,tot1;
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        int sum0=1,sum1=1;
        scanf("%d",&n);
        if(!n) {puts("1");continue;}
        for(int i=1;i<=n;i++) scanf("%d",a+i);
        s0[tot0=0]=node(inf,1);//增
        s1[tot1=0]=node(-inf,1);
        for(int i=2;i<=n;i++)
            if(a[i]>a[i-1])//得把那個s1推了
            {
                int t0=a[i]>s1[0].val?s1[0].cnt:0;
                int t1=a[i]<s0[0].val?s0[0].cnt:0;
                while(tot1) (t0+=a[i]>s1[tot1].val?s1[tot1].cnt:0)%=mod,--tot1;
                s0[++tot0]=node(a[i-1],t0);
                s1[tot1=0]=node(a[i-1],t1);
                (sum0+=t0)%=mod,sum1=t1;
            }
            else
            {
                int t0=a[i]>s1[0].val?s1[0].cnt:0;
                int t1=a[i]<s0[0].val?s0[0].cnt:0;
                while(tot0) (t1+=a[i]<s0[tot0].val?s0[tot0].cnt:0)%=mod,--tot0;
                s0[tot0=0]=node(a[i-1],t0);
                s1[++tot1]=node(a[i-1],t1);
                sum0=t0,(sum1+=t1)%=mod;
            }
        printf("%d\n",(sum0+sum1)%mod);
    }
    return 0;
}

2019.1.1