CSU 1807 最长上升子序列~
来源:互联网 发布:139端口基于什么协议 编辑:程序博客网 时间:2024/05/29 15:10
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
先递推出dp[i]表示长度为i且最长上升子序列的长度恰好为 (n-1) 的序列的个数。
考虑第i个数放的位置,如果放在第i位,那么有dp[i-1]种,如果放在i-1位,有i-1种
放在前面i-2个位置分别有一种,所以dp[i]=dp[i-1]+2i-3;
对于一个长度为n的合法序列来说,必然是从有序的1,2,3,4,5..n
这个数列中向前或向后移动某一个数字得到的
所以对于给出的序列,分类讨论
1.如果有某个数字偏离值超过1,那么显然此时答案是只有1种或没有,判断一下即可。
2.如果有某两个数字偏离分别是+1和-1,那么同上,判断一下即可。
3.如果有偏离,判断是-1的还是+1的,对于这种情况,
找出最左和最右的偏离,并且中间有的数也必须是偏离的,
然后答案是左边可用的空间和右边可用的空间的乘积。
4.没有任何位置有偏移,那么找出全部连续的可用空间,把对应的dp值加起来即可。
#include<set>#include<map>#include<ctime>#include<cmath>#include<stack>#include<queue>#include<bitset>#include<cstdio>#include<string>#include<cstring>#include<iostream>#include<algorithm>#include<functional>#define rep(i,j,k) for (int i = j; i <= k; i++)#define per(i,j,k) for (int i = j; i >= k; i--)#define loop(i,j,k) for (int i = j;i != -1; i = k[i])#define lson x << 1, l, mid#define rson x << 1 | 1, mid + 1, r#define ff first#define ss second#define mp(i,j) make_pair(i,j)#define pb push_back#define pii pair<int,int>#define in(x) scanf("%d", &x);using namespace std;typedef long long LL;const int low(int x) { return x&-x; }const double eps = 1e-8;const int INF = 0x7FFFFFFF;const int mod = 1e9 + 7;const int N = 1e5 + 10;int n, a[N];LL dp[N];void init(){dp[0] = dp[1] = 0; rep(i, 2, N - 1) dp[i] = dp[i - 1] + 2 * i - 3;}int check(int x){int now = 1;rep(i, 1, n){if (now == a[x]) ++now;if (i == x) continue;if (a[i] && a[i] != now) return 0;++now;}return 1;}int check(int x, int y){if (x != y - 1) return 0;rep(i, 1, n){if (i == x || i == y) continue;if (a[i] && a[i] != i) return 0;}return 1;}LL get(int x, int y){int l = n + 1, r = 0;rep(i, 1, n) if (a[i] && a[i] != i) l = min(l, i), r = max(r, i);rep(i, l, r) if (a[i] && a[i] == i) return 0;int L = l, R = n - r + 1;per(i, l, 1) if (a[i] == i) { L = l - i; break; }rep(i, r, n) if (a[i] == i) { R = i - r; break; }return 1LL * (L - x) * (R - y);}LL get(){LL res = 0, now = 0;rep(i, 1, n) if (a[i]) res += dp[a[i] - now - 1], now = a[i];return res + dp[n - now];}int main(){init();while (scanf("%d", &n) != EOF){int flag = 0, l = 0, r = 0;rep(i, 1, n){scanf("%d", &a[i]);if (!a[i]) continue;if (abs(a[i] - i) > 1) flag = i;if (a[i] - i == 1) l = i;if (i - a[i] == 1) r = i;}if (flag) { printf("%d\n", check(flag)); continue; }if (l&&r) { printf("%d\n", check(l, r)); continue; }if (l || r) { printf("%lld\n", get(!l, !r)); continue; }printf("%lld\n", get());}return 0;}
0 0
- CSU 1807: 最长上升子序列~
- CSU 1807 最长上升子序列~
- CSU 1120 病毒 最长公共上升子序列(LCIS)
- CSU 1047 最长上升子序列 (二分水过)
- 【模拟】CSU 1807 最长上升子序列~ (2016湖南省第十二届大学生计算机程序设计竞赛)
- 湖南省第12届大学生计算机程序设计大赛 最长上升子序列 csu 1807
- 最长上升子序列
- 最长上升子序列
- 最长上升子序列
- 最长上升子序列
- 最长上升子序列
- 最长上升子序列
- 最长上升子序列
- 最长上升子序列
- 最长上升子序列
- 最长上升子序列
- 最长上升子序列
- 最长上升子序列
- C#入门12.1——创建Winform程序
- 进程与线程的一个简单解释
- 架构漫谈(九):理清技术、业务和架构的关系
- Description Resource Path Location Type Archive for required library: 'C:/Users/simran/.m2/
- java2.12.2实验2(输出希腊字母表)
- CSU 1807 最长上升子序列~
- Android动画学习心得
- Session攻击手段(会话劫持/固定)及其安全防御措施
- @scheduled定时任务
- Git管理多个远端仓库的方法
- Unrooted Tests:使用jUnit进行单元测试时遇到的问题
- java1.12.3实验3(从键盘输入数据)Scanner工具类
- SGU 153 Playing with matches (博弈,循环节)
- 查询表单输入是否已存在