您的位置:首页 > 其它

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

2016-09-06 11:30 176 查看

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
,b
,m
;
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: