2017 ACM-ICPC 亚洲区(南宁赛区)网络赛 L题 非递减权值最大
Let S be a sequence of integers s1, s2, ..., sn Each integer is is associated with a weight by the following rules:
(1) If is is negative, then its weight is 0.
(2) If is is greater than or equal to 10000, then its weight is 5. Furthermore, the real integer value of si is si−10000 . For example, if si is 10101, then is is reset to 101 and its weight is 5.
(3) Otherwise, its weight is 1.
A non-decreasing subsequence of S is a subsequence si1, si2, ..., sik, with i1<i2 ... <ik, such that, for all 1≤j<k, we have sij<sij+1.
A heaviest non-decreasing subsequence of S is a non-decreasing subsequence with the maximum sum of weights.
Write a program that reads a sequence of integers, and outputs the weight of its
heaviest non-decreasing subsequence. For example, given the following sequence:
80 75 73 93 73 73 10101 97 −1 −1 114 −1 10113 118
The heaviest non-decreasing subsequence of the sequence is <73,73,73,101,113,118> with the total weight being 1+1+1+5+5+1=14. Therefore, your program should output 14 in this example.
We guarantee that the length of the sequence does not exceed 2∗105
Input Format
A list of integers separated by blanks:s1, s2,...,sn
Output Format
A positive integer that is the weight of the heaviest non-decreasing subsequence.
样例输入
80 75 73 93 73 73 10101 97 -1 -1 114 -1 10113 118
样例输出
14
题目来源
负数不用考虑 直接去掉就可以,
问非递减序列, 中 权值最大是多少;
刚开始理解错了 用到而是 nlog(n) 算法找的 最长上升子序列,然后找的权值,
但是这样不能保证权值最大;
一个很巧妙的方法就是: 权值是5 我们可以 拆分成5 个相同的数 使权值为1 这样 所有的权值都是1
就变成找 最长上升子序列了
n^n 超时
还有一种方法就是 动态规划来做
第二层 用树状数组来维护 前面的最大值
代码:
#include <iostream> #include <stdio.h> #include <algorithm> #include <cmath> #include <math.h> #include <cstring> #include <string> #include <queue> #include <stack> #include <stdlib.h> #include <list> #include <map> #include <set> #include <bitset> #include <vector> #define mem(a,b) memset(a,b,sizeof(a)) #define findx(x) lower_bound(b+1,b+1+bn,x)-b #define FIN freopen("input.txt","r",stdin) #define FOUT freopen("output.txt","w",stdout) #define S1(n) scanf("%d",&n) #define SL1(n) scanf("%I64d",&n) #define S2(n,m) scanf("%d%d",&n,&m) #define SL2(n,m) scanf("%I64d%I64d",&n,&m) #define Pr(n) printf("%d\n",n) using namespace std; typedef long long ll; const int INF=0x3f3f3f3f; const double esp=1e-6; const int maxn=1e6+5; const int MOD=1e9+7; const int mod=1e9+7; int dir[5][2]={0,1,0,-1,1,0,-1,0}; struct node{ int x,y; }a[maxn]; int stacks[maxn]; int main() { int x; int k=0; while((scanf("%d",&x))!=EOF) { if(x<10000&&x>=0) a[k].x=x,a[k++].y=1; else if(x<0) continue; else if(x>=10000) { for(int i=1;i<=5;i++) a[k].x=x-10000,a[k++].y=1; } } stacks[0]=-1; int n=k-1; int top=0; int temp; for (int i = 0; i <=n; i++) { temp=a[i].x; if (temp >= stacks[top]) { stacks[++top] = temp; } else { int low = 1, high = top; int mid; while(low <= high) { mid = (low + high) / 2; if (temp >= stacks[mid]) { low = mid + 1; } else { high = mid - 1; } } stacks[low] = temp; } } cout<<top<<endl; return 0; } /* 75 73 93 73000 10101 97 -1 102 114 -1 10113 118 */
树状数组 解法:
【代码】:
#include <iostream> #include <stdio.h> #include <algorithm> #include <cmath> #include <math.h> #include <cstring> #include <string> #include <queue> #include <stack> #include <stdlib.h> #include <list> #include <map> #include <set> #include <bitset> #include <vector> #define mem(a,b) memset(a,b,sizeof(a)) #define findx(x) lower_bound(b+1,b+1+bn,x)-b #define FIN freopen("input.txt","r",stdin) #define FOUT freopen("output.txt","w",stdout) #define S1(n) scanf("%d",&n) #define SL1(n) scanf("%I64d",&n) #define S2(n,m) scanf("%d%d",&n,&m) #define SL2(n,m) scanf("%I64d%I64d",&n,&m) #define Pr(n) printf("%d\n",n) using namespace std; typedef long long ll; const double PI=acos(-1); const int INF=0x3f3f3f3f; const double esp=1e-6; const int maxn=1e6+5; const int MAX=50005; const int MOD=1e9+7; const int mod=1e9+7; int dir[5][2]={0,1,0,-1,1,0,-1,0}; ll inv[maxn*2]; void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){ x=1; y=0; d=a; }else{ ex_gcd(b,a%b,d,y,x); y-=x*(a/b);}} ll gcd(ll a,ll b){ return b?gcd(b,a%b):a;} ll exgcd(ll a,ll b,ll &x,ll &y){if(!b){x=1;y=0;return a;}ll ans=exgcd(b,a%b,x,y);ll temp=x;x=y;y=temp-a/b*y;return ans;} ll lcm(ll a,ll b){ return b/gcd(a,b)*a;} ll qpow(ll x,ll n){ll res=1;for(;n;n>>=1){if(n&1)res=(res*x)%MOD;x=(x*x)%MOD;}return res;} ll inv_exgcd(ll a,ll n){ll d,x,y;ex_gcd(a,n,d,x,y);return d==1?(x+n)%n:-1;} ll inv1(ll b){return b==1?1:(MOD-MOD/b)*inv1(MOD%b)%MOD;} ll inv2(ll b){return qpow(b,MOD-2);} struct math_tree{ int n; int a[MAX],Max[MAX],Min[MAX]; int tree[MAX]; void init(int N) { n=N; for(int i=0;i<=N;i++) Max[i]=-(Min[i]=INF); } void update(int k,int num)//单点更新 { a[k]=num; while(k<=n) { tree[k]+=num; Min[k]=Max[k]=a[k]; int lk=k&(-k); for(int i=1;i<lk;i<<=1) { Max[k]=max(Max[k],Max[k-i]); Min[k]=min(Min[k],Min[k-i]); } k+=k&(-k);// lowbit(k)= k&(-k); } } int Sum(int k) { int sum=0; while(k) { sum+=tree[k]; k-=k&-k; } return sum; } int Get_Sum(int x,int y) { return Sum(y)-Sum(x-1); } int Qmax(int x,int y)//[x,y]区间最大值 { int ans=-INF; while(y>=x) { ans=max(a[y], ans); y--; for(;y-(y&-y)>=x;y-=(y&-y)) ans=max(Max[y],ans); } return ans; } int Qmin(int x,int y)//[x,y] 区间最小值 { int ans=INF; while(y>=x) { ans=min(a[y],ans); y--; for(;y-(y&-y)>=x;y-=(y&-y)) ans=min(ans,Min[y]); } return ans; } }A; int a[maxn],b[maxn]; int main() { int x; int dp; int k=1; int top=0; while(scanf("%d",&x)!=EOF) { if(x<0) continue; else if(x>=10000) { a[k]=x-10000; b[k]=5; } else a[k]=x,b[k]=1; top=max(a[k],top); k++; } int n=k-1; math_tree ans; ans.init(top); for(int i=1;i<=n;i++) { dp=b[i]+ans.Qmax(1,a[i]);// 前a[i] 最大值 ans.update(a[i],dp);// 更新 最大值 } printf("%d\n",ans.Qmax(1,top)); return 0; }
123