2016多校联合第三场 HDU5760
来源:互联网 发布:网络借贷安全班会 编辑:程序博客网 时间:2024/06/06 04:10
给你个n ,然后n 个数,你要找到一个最长的序列s ,输出其长度,并且输出不同的s 的个数。s 序列必须是回文的,并且中间最小,往两边依次增大,可以相等。s1 与s2 不同当且仅当长度不同或者存在某位s1[i]!=s2[i]
这个dp比较难。
n范围比较小,先把a 数组离散化。方便之后处理。再预处理两个数组pre[i][j] nxt[i][j] 分别表示以i 起左边第一个等于j的数的位置和以i 起右边第一个等于j的数的位置。
设dp[l][r] 元组表示a[l]==a[r] 的时候的最长s串和最长串个数。那么有dp[l][r]=max{dp[nxt[l][c]][pre[r][c]]+2} 枚举c再枚举区间的复杂度是n3 显然超时。
如果固定l ,逐渐向右扫的时候,dp 值肯定是越来越优的。我们设一个临时变量ans 来表示l 右边开始某位置的最优值,然后往右扫的同时就可以直接用此临时变量更新我们的dp[l][r] ,当然,也需要把ans 的值也更新。当遇到相同值的时候,要加上数量,然后就是去重
每次更新ans 的时候,如果发现当前串的长度等于ans 那么需要把个数加进ans 但是如果之前加过一样的长度,并且二者首尾一样,那么说明后者包含了更多的res (因为范围更大)那么减去原来的,加上后来的,刚好不重不漏。
//// Created by Running Photon// Copyright (c) 2015 Running Photon. All rights reserved.//#include <algorithm>#include <cctype>#include <cmath>#include <cstdio>#include <cstdlib>#include <cstring>#include <iomanip>#include <iostream>#include <map>#include <queue>#include <string>#include <sstream>#include <set>#include <vector>#include <stack>#define ALL(x) x.begin(), x.end()#define INS(x) inserter(x, x,begin())#define ll long long#define CLR(x) memset(x, 0, sizeof x)using namespace std;const int inf = 0x3f3f3f3f;const int MOD = 1e9 + 7;const int maxn = 1e6 + 10;const int maxv = 5e3 + 10;const double eps = 1e-9;int a[maxv];int pre[maxv][maxv], nxt[maxv][maxv];typedef pair <int, int> sta;sta dp[maxv][maxv];int main() {#ifdef LOCAL freopen("C:\\Users\\Administrator\\Desktop\\in.txt", "r", stdin); freopen("C:\\Users\\Administrator\\Desktop\\out.txt","w",stdout);#endif// ios_base::sync_with_stdio(0); int n; while(scanf("%d", &n) != EOF) { std::vector<int> xs; for(int i = 1; i <= n; i++) { int x; scanf("%d", &x); xs.push_back(x); a[i] = x; } sort(ALL(xs)); xs.resize(unique(ALL(xs)) - xs.begin()); for(int i = 1; i <= n; i++) { a[i] = lower_bound(ALL(xs), a[i]) - xs.begin() + 1; } // for(int i = 1; i <= n; i++) { // printf("%d ", a[i]); // } // puts(""); memset(pre, -1, sizeof pre); memset(nxt, -1, sizeof nxt); int big = xs.size(); for(int i = 0; i <= n + 1; i++) { for(int j = i + 1; j <= n; j++) { if(nxt[i][a[j]] == -1) { nxt[i][a[j]] = j; } } for(int j = i - 1; j > 0; j--) { if(pre[i][a[j]] == -1) { pre[i][a[j]] = j; } } } for(int i = n; i > 0; i--) { dp[i][i] = sta(1, 1); sta ans = sta(0, 1); for(int j = i + 1; j <= n; j++) { dp[i][j] = sta(0, 0); if(a[i] == a[j]) { // printf("dp[%d][%d] = %d %d\n", i, j, dp[i][j].first, dp[i][j].second); dp[i][j] = sta(ans.first + 2, ans.second); } if(a[i] >= a[j]) { int head = nxt[i][a[j]]; if(head == -1) continue; if(dp[head][j].first > ans.first) { ans = dp[head][j]; } else if(dp[head][j].first == ans.first) { int p = pre[j][a[j]]; if(p != -1 && dp[head][p].first == dp[head][j].first) ans.second -= dp[head][p].second; if(ans.second < 0) ans.second += MOD; ans.second = (ans.second + dp[head][j].second) % MOD; } } } } sta ans(0, 0); for(int c = 1; c <= big; c++) { int head = nxt[0][c]; int tail = pre[n+1][c]; if(head == -1 || tail == -1) continue; // printf("dp[%d][%d] = %d\n", head, tail, dp[head][tail]); if(ans.first < dp[head][tail].first) { ans = dp[head][tail]; } else if(ans.first == dp[head][tail].first) { ans.second = (ans.second + dp[head][tail].second) % MOD; } } printf("%d %d\n", ans.first, ans.second); } return 0;}
0 0
- 2016多校联合第三场 HDU5760
- 多校联合第三场
- 2016多校联合第三场 HDU5758 Explorer Bo
- 2013多校联合训练第三场
- 2014多校联合-第三场
- 2013暑期多校联合训练\第三场\Problem G
- 2013暑期多校联合训练\第三场\Problem H
- 2013年HDU多校联合第三场解题报告
- [dfs]多校联合第三场 K Work
- [数学]多校联合第三场 hdu5317 RGCDQ
- [模拟] 多校联合第三场 painter HDU 5319
- 2015多校联合训练第三场Work(hdu5326)
- 2015多校联合训练第三场Painter(hdu5319)
- 2015多校联合第三场 hdu5317 RGCDQ
- 2015多校联合第三场5319painter
- 2016多校联合训练赛 第三场1010 Rower Bo hdu 5761
- 2016多校联合第二场
- 2016多校联合第四场 HDU5768
- 笔记 - JRebel for android
- 多个Activity之间共享数据的5种方式以及 Application Context
- Red packet~二分
- ipc
- Codeforces Round #202 (Div. 1) A. Mafia 【二分】
- 2016多校联合第三场 HDU5760
- pytho序列,字符串,元组---学习笔记
- 树莓派上跑rplidar
- 统 一代码格式
- C语言数据类型
- 关于网上一些关于内存泄漏和内存溢出资料整理(一)
- Hibernate二级缓存配置
- 安装jupyter notebook
- oracle服务占用8080端口