CSU 1807: 最长上升子序列~

来源:互联网 发布:md5码算法 编辑:程序博客网 时间:2024/05/29 15:43

Description

Bobo 在 ICPCCamp 学会了解决最长上升子序列问题后得到了一个长度为 n 的数列 p1,p2,…,pn.
Bobo 想用 1,2,…,n 来替换其中值为 0 的元素,使得 p1,p2,…,pn 互不相同(即 p1,p2,…,pn 是 {1,2,…,n} 的排列)。
现在 Bobo 想知道,替换后最长上升子序列的长度恰好为 (n-1) 数列的数量。

Input

输入包含不超过 300 组数据,其中不超过 20 组的 n 超过 100.
每组数据的第一行包含一个整数 n (1≤n≤105).
第二行包含 n 个整数p1,p2,…,pn  (0≤pi≤n).
保证p1,p2,…,pn中非 0 的元素互不相同。

Output

对于每组数据,输出一个整数表示要求的值。

Sample Input

30 0 040 0 0 051 0 0 4 5

Sample Output

491

HINT

Source

湖南省第十二届大学生计算机程序设计竞赛


思路:很显然,要形成最长长度为n-1的上升序列,就是要将原来的自然序列中的某一个数,插入到相对于原来位置的其他位置中去,可以再最前面和最后面,这样就能保证最长上升子序列长度为n-1,,对于输入的a数组分情况讨论,a[i] = 0不影响,分的情况不讨论a[i] = 0的情况

对于自然序列1 2 3 4 .... i   i+1.... i+j......n
形成n-1的长度可以转换为
1 2 3 ..... i+j  i  i+1 ... i+j-1....n
或者1 2 3 ......i+1 i+2......i+j  i......n
其中有一段子段左移一位或者右移一位

(1)对于所有 a[i] == i
这种情况只需要对连续的0作为一个子串进行变换,很容易得出结果

(2)a[i] != i && abs(a[i] - i) > 1
由于是将某一个数插入到某个位置,那么如果存在abs(a[i] - i) > 1那么一定是由某个数的插入的到这个位置而不是某个子段移动得到

(3) 只剩下a[i] != i&& abs(a[i] - i) = 1的情况
这种情况有可能是长度为1的子段固定移动而来,对这种情况进行特殊判断
剩下的只可能某个连续的子段移动而来,计算这个结果即可

#include<cstdio>#include<cstring>#include<cmath>#include<map>#include<string>#include<stack>#include<vector>#include<queue>#include<set>#include<algorithm>#include<iostream>const int maxn = 1e5 + 10;typedef long long ll;using namespace std;ll a[maxn], b[maxn], n;int main(){    while(scanf("%lld", &n) != EOF) {        ll s1 = 0, s2 = 0, ind = -1;        ll f = 1;        for(ll i = 1; i <= n; i++) {            scanf("%lld", &a[i]);            b[i] = a[i];            if(!a[i] || a[i] - i == 0) continue;            ll c = a[i] - i;            f = 0;            if(ind < 0) ind = i;            if(abs(c) > 1) ind = i;        }        if(!f) {            if(abs(a[ind] - ind) > 1) {                ll sign = 1, ty = a[ind];                //恢复自然序列                if(a[ind] < ind) {                    for(ll i = ind; i > a[ind]; i--)                        b[i] = b[i - 1];                    b[ty] = ty;                } else {                    for(ll i = ind; i < a[ind]; i++)                        b[i] = b[i + 1];                    b[ty] = ty;                }                for(ll i = 1; i <= n; i++) {                    if(!b[i]) continue;                    if(b[i] != i) sign = 0;                }                printf("%lld\n", sign);            } else {                //固定交换而来                if(ind < n && a[ind + 1] && (a[ind] - ind) * (a[ind + 1] - ind - 1) == -1) {                    ll sign = 1;                    swap(b[ind], b[ind + 1]);                    for(ll i = 1; i <= n; i++) {                        if(!b[i]) continue;                        if(b[i] != i) sign = 0;                    }                    printf("%lld\n", sign);                } else {                    ll sign = 1, sum = 0;                    ll id1 = ind, id2 = ind; //两个边界                    for( ; id1 >= 1 && a[id1] != id1; id1--);                    for( ; id2 <= n && a[id2] != id2; id2++);                    for(ll i = id1 - 1; i >= 1; i--) {                        if(!a[i]) continue;                        if(a[i] != i) sign = 0;                    }                    for(ll i = id2 + 1; i <= n; i++) {                        if(!a[i]) continue;                        if(a[i] != i) sign = 0;                    }                    if(sign) {                        ll idx = ind;                        //ind ~ idx整体移动的序列的长度                        for(ll i = ind; i <= n; i++)                            if(a[i] - i == a[ind] - ind) idx = i;                        if(a[ind] < ind) {                            sum = (id2 - idx) * (ind - id1 - 1);                        } else {                            sum = (ind - id1) * (id2 - idx - 1);                        }                    }                    printf("%lld\n", sum);                }            }        } else {            ll d = 1, sum = 0;            while(d < n) {                if(a[d]) { d++; continue; }                ll i = d;                for( ; i <= n && !a[i]; i++);                i--;                sum += (i - d) * (i - d);                d = i + 1;            }            printf("%lld\n", sum);        }    }    return 0;}


0 0
原创粉丝点击