BZOJ 1609 [Usaco2008 Feb]Eating Together麻烦的聚餐:LIS & LDS (nlogn)
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1609
题意:
给你一个只由数字"1,2,3"组成的序列a[i],共n个数。
你可以任意更改这些数字,使得序列中每一种数字都“站在一起”,并且单调不减或不增。
例如:"1111222", "332211"...
问你至少更改多少个数字。
题解:
单调不减:求原序列LIS(最长非降子序列),当前答案t1 = n - LIS.
单调不增:求原序列LDS(最长非升子序列),当前答案t2 = n - LDS.
最终答案ans = min(t1,t2).
注:n为30000,求LIS & LDS用nlogn方法。
AC Code:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #define MAX_N 30005 5 6 using namespace std; 7 8 int n; 9 int a[MAX_N]; 10 int d[MAX_N]; 11 12 int cal_lis() 13 { 14 int len=1; 15 d[1]=a[0]; 16 for(int i=1;i<n;i++) 17 { 18 if(a[i]>=d[len]) 19 { 20 d[++len]=a[i]; 21 continue; 22 } 23 int lef=1; 24 int rig=len; 25 while(rig-lef>1) 26 { 27 int mid=(lef+rig)/2; 28 if(a[i]>=d[mid]) lef=mid; 29 else rig=mid; 30 } 31 int ans; 32 if(a[i]<d[lef]) ans=0; 33 else ans=lef; 34 d[ans+1]=min(d[ans+1],a[i]); 35 } 36 return len; 37 } 38 39 int cal_lds() 40 { 41 int len=1; 42 d[1]=a[0]; 43 for(int i=1;i<n;i++) 44 { 45 if(a[i]<=d[len]) 46 { 47 d[++len]=a[i]; 48 continue; 49 } 50 int lef=1; 51 int rig=len; 52 while(rig-lef>1) 53 { 54 int mid=(lef+rig)/2; 55 if(a[i]<=d[mid]) lef=mid; 56 else rig=mid; 57 } 58 int ans; 59 if(a[i]>d[lef]) ans=0; 60 else ans=lef; 61 d[ans+1]=max(d[ans+1],a[i]); 62 } 63 return len; 64 } 65 66 int main() 67 { 68 cin>>n; 69 for(int i=0;i<n;i++) 70 { 71 cin>>a[i]; 72 } 73 int v1=cal_lis(); 74 int v2=cal_lds(); 75 cout<<n-max(v1,v2)<<endl; 76 }