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

posted @ 2019-01-01 10:51  露迭月  阅读(209)  评论(0编辑  收藏  举报