Codeforces Beta Round #4 (Div. 2 Only) D. Mysterious Present(LIS)
题意:
现在我们有 n 个信封,然后我们有一张卡片,并且我们知道这张卡片的长和宽。
现给出这 n 个信封的长和宽,我们想形成一个链,这条链的长度就是这条链中所含有的信封的数量;
但是需要满足①信封a可以连接信封b当且仅当信封a的长和宽分别严格小于信封b的长和宽。
②构成这条长链的所有信封的长和宽分别严格小于卡片的长和宽。
问最多可以形成多长的链,并且输出我们选取的链的编号;
题解:
DAG上的动态规划;
如果信封对于任意两个信封 a,b 满足上述条件①②,那么连一条由a指向b的有向边;
O(n2)预处理出所有满足条件的(a,b);
求解DAG上的最长路;
正解,nice,可你别忘了,最大需要开 n2 = 25000000 的数组存图,emmm;
然后,不断地试探,最终
啊,最后一个点,翻车了;
出题人也太坏了叭;
正解:首先对于这 n 个信封,按照 w 从小到大排序,然后,找 h 的最长上升子序列;
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define memF(a,b,n) for(int i=0;i <= n;a[i]=b,++i); 4 const int maxn=5e3+50; 5 6 int n,w,h; 7 struct Date 8 { 9 int w,h; 10 int id; 11 bool operator < (const Date& obj) const 12 { 13 return w < obj.w; 14 } 15 }_date[maxn]; 16 int dp[maxn]; 17 18 bool isSat(int i,int j) 19 { 20 return _date[i].w < _date[j].w && _date[i].h < _date[j].h; 21 } 22 void Solve() 23 { 24 sort(_date+1,_date+n+1); 25 memF(dp,1,n); 26 for(int i=n-1;i >= 1;--i) 27 for(int j=i+1;j <= n;++j) 28 if(isSat(i,j)) 29 dp[i]=max(dp[j]+1,dp[i]); 30 31 int ans=0; 32 int cur; 33 for(int i=1;i <= n;++i) 34 if(isSat(0,i) && dp[i] > ans) 35 { 36 ans=dp[i]; 37 cur=i; 38 } 39 40 printf("%d\n",ans); 41 if(ans == 0) 42 return ; 43 44 printf("%d",_date[cur].id); 45 for(int i=1;i <= n;++i) 46 if(dp[i] == dp[cur]-1 && isSat(cur,i)) 47 printf(" %d",_date[i].id),cur=i; 48 printf("\n"); 49 } 50 int main() 51 { 52 scanf("%d%d%d",&n,&w,&h); 53 for(int i=1;i <= n;++i) 54 { 55 scanf("%d%d",&_date[i].w,&_date[i].h); 56 _date[i].id=i; 57 } 58 _date[0]={w,h}; 59 60 Solve(); 61 62 return 0; 63 }