CSU 1807: 最长上升子序列~ 分类讨论

 

1807: 最长上升子序列~

Time Limit: 5 Sec  Memory Limit: 128 MB
Submit: 138  Solved: 17
[Submit][Status][Web Board]

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

3
0 0 0
4
0 0 0 0
5
1 0 0 4 5

Sample Output

4
9
1

HINT

Source

[Submit][Status][Web Board]

分析:就是大分类讨论,考虑偏移

#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1e5 + 5;
const double eps = 1e-9;
const double INF = 1e12;
int n,a[N],b[N],m[N];
void solve3(int id){
   memset(b,0,sizeof(b));
   b[id] = a[id];int cnt=0;
   for(int i=1;i<=n;++i){
     if(i==id)continue;
     ++cnt;if(cnt==a[id])++cnt;
     b[i]=cnt;
   }
   for(int i=1;i<=n;++i)
    if(a[i]&&a[i]!=b[i]){
        puts("0");
        return;
    }
   puts("1"); 
}
void solve1(int id){
  if(a[id+1]==id){
     for(int i=1;i<=n;++i){
        b[i]=i;
     }
     swap(b[id],b[id+1]);
     for(int i=1;i<=n;++i){
       if(a[i]&&a[i]!=b[i]){
         puts("0");return;
       }
     }
     puts("1");
     return;
  }
  int r=id,flag=0;
  for(int i=id+1;i<=n;++i){
    if(a[i] == 0)continue;
    if(i!=a[i]){
      if(!flag&&a[i]==i+1)r=i;
      else{
          puts("0");
          return;
      }
    }
    if(i==a[i])flag=1;
  }
  int t1 = 0,t2 = 0;
  for(int i= id-1;i&&a[i]==0;--i)++t1;
  for(int i=r+1;i<=n&&a[i]==0;++i)++t2;
  LL ret = 1ll*(t1+1)*t2;
  printf("%lld\n",ret);
}
void solve2(int id){
   if(a[id-1]==id){
     for(int i=1;i<=n;++i){
        b[i]=i;
     }
     swap(b[id],b[id-1]);
     for(int i=1;i<=n;++i){
       if(a[i]&&a[i]!=b[i]){
         puts("0");return;
       }
     }
     puts("1");
     return;
  }
  int r=id,flag=0;
  for(int i=id+1;i<=n;++i){
    if(a[i]==0)continue;
    if(i!=a[i]){
      if(!flag&&a[i]==i-1)r=i;
      else{
         puts("0");
         return;
      }
    }
    if(i==a[i])flag=1;
  }
  int t1 = 0,t2 = 0;
  for(int i=id-1;i&&a[i]==0;--i)++t1;
  for(int i=r+1;i<=n&&a[i]==0;++i)++t2;
  LL ret = 1ll*(t2+1)*t1;
  printf("%lld\n",ret);
}
int main(){
  while(~scanf("%d",&n)){
    memset(m,-1,sizeof(m));
    for(int i=1;i<=n;++i)scanf("%d",&a[i]),m[a[i]]=i;
    bool flag = false;
    for(int i=1;i<=n;++i){
      if(a[i]&&(a[i]-i>1||i-a[i]>1)){
         solve3(i);
         flag = true;
         break;
      }
    }
    if(flag)continue;
    for(int i=1;i<=n;++i){
      if(a[i]==0||a[i]==i)continue;
      if(a[i]-i==1)solve1(i);
      else if(i-a[i]==1)solve2(i);
      flag = true;
      break;
    }
    if(flag)continue;
    int cnt=0;LL ret=0;
    for(int i=1;i<=n;++i){
      if(a[i]==0)++cnt;
      else if(cnt){
        ret+=1ll*(cnt-1)*(cnt-1);
        cnt=0;
      }
    }
    if(cnt)ret+=1ll*(cnt-1)*(cnt-1);
    printf("%lld\n",ret);
  }
  return 0;
}
View Code

 

posted @ 2016-09-06 11:30  shuguangzw  阅读(400)  评论(0编辑  收藏  举报