CSU 1807: 最长上升子序列~ 分类讨论
1807: 最长上升子序列~
Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 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
分析:就是大分类讨论,考虑偏移
#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; }