<span>uva12018 Juice Extractor(dp)</span>
题意:
1000个水果,有lr时间,每次切都要清屏,3个或以上记录分数,问最高得分
感慨:
本来这中sb题不想写博客。。然而。。。。。。。。。。。。。。。
这个sb题由于其他队过了,然后我觉得挺有意思问了他们题意拿来做了下,
他们说的题意其他都一样就是还要游戏过程中不能漏掉水果,必须全都切掉,不能让他们掉下去!!!
然后我写完之后莫名的wa(黑人??),过了一会,另一个队友听了同样的题意后暴力n^2logn卡过了,
然后我(黑人???)我就一直在检查bug,检查了3个多小时!!!!!!!!!
然后我实在是觉得我的代码没啥问题了,就扫兴地看了下题意,然后我满眼放光 - - - - -
居然他们理解的题意是错的。。。
我实在是佩服他们是怎么过的题。。还有那个卡过的。。。。
用错误的代码过了错误的题,这也是一种能力吧~~~~~~~~~~
这个题是我唯一一个思路逻辑非常清晰然后莫名wa还一直发现不了错误的题了
然后我稍微的改动了一下代码。。。。。。。。。
思路:
如果按正确题意的话,你只需要离散化时间,然后n^2预处理通过任意两个时间点的水果数,然后n^2的裸dp就可以了
(可能还是很复杂,不过我不想再重新想别的更简单的做法了)
时间复杂度(O(n^2))
/* *********************************************** Author :devil ************************************************ */ #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #include <stack> #include <map> #include <unordered_map> #include <string> #include <time.h> #include <cmath> #include <stdlib.h> #define LL long long #define rep(i,a,b) for(int i=a;i<=b;i++) #define dep(i,a,b) for(int i=a;i>=b;i--) #define ou(a) printf("%d\n",a) #define pb push_back #define pii pair<int,int> #define mkp make_pair #define IN freopen("in.txt","r",stdin); #define OUT freopen("out.txt","w",stdout); using namespace std; const int inf=0x3f3f3f3f; const int mod=1e9+7; const int N=1e3+10; int t,n,tmp[N*2],sum[N*2][N*2],dp[N*2]; struct wq { int l,r; }l[N]; int main() { scanf("%d",&t); for(int cas=1;cas<=t;cas++) { int m=0,ans=0; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d%d",&l[i].l,&l[i].r); tmp[++m]=l[i].l; tmp[++m]=l[i].r; } sort(tmp+1,tmp+m+1); m=unique(tmp+1,tmp+m+1)-tmp-1; memset(sum,0,sizeof(sum)); for(int i=1;i<=n;i++) { l[i].l=lower_bound(tmp+1,tmp+m+1,l[i].l)-tmp; l[i].r=lower_bound(tmp+1,tmp+m+1,l[i].r)-tmp; for(int j=l[i].l;j<=l[i].r;j++) sum[j][l[i].l]++; } for(int i=1;i<=m;i++) for(int j=1;j<=i;j++) sum[i][j]+=sum[i][j-1]; memset(dp,0,sizeof(dp)); for(int i=1;i<=m;i++) { if(sum[i][i]>=3) dp[i]=sum[i][i]; for(int j=1;j<i;j++) { if(sum[i][i]-sum[i][j]>=3) dp[i]=max(dp[i],dp[j]+sum[i][i]-sum[i][j]); else dp[i]=max(dp[i],dp[j]); } ans=max(ans,dp[i]); } printf("Case #%d: %d\n",cas,ans); } return 0; }
如果按错误题意的话,你需要在这基础上对左右端点按右端点排序,然后更新dp的时候,需要找一个左边界l,这个l就是
所有在i这个时间点已经消失的水果的最大的起始时间。这样才能保证你在切当前这一刀的时候,上一刀不会漏掉水果,让水果掉下去。
时间复杂度(O(n^2))
/* *********************************************** Author :devil ************************************************ */ #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #include <stack> #include <map> #include <unordered_map> #include <string> #include <time.h> #include <cmath> #include <stdlib.h> #define LL long long #define rep(i,a,b) for(int i=a;i<=b;i++) #define dep(i,a,b) for(int i=a;i>=b;i--) #define ou(a) printf("%d\n",a) #define pb push_back #define pii pair<int,int> #define mkp make_pair #define IN freopen("in.txt","r",stdin); #define OUT freopen("out.txt","w",stdout); using namespace std; const int inf=0x3f3f3f3f; const int mod=1e9+7; const int N=1e3+10; int t,n,tmp[N*2],sum[N*2][N*2],dp[N*2]; struct wq { int l,r; }l[N]; bool cmp(wq a,wq b) { if(a.r!=b.r) return a.r<b.r; return a.l>b.l; } int main() { scanf("%d",&t); for(int cas=1;cas<=t;cas++) { int m=0; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d%d",&l[i].l,&l[i].r); tmp[++m]=l[i].l; tmp[++m]=l[i].r; } sort(tmp+1,tmp+m+1); m=unique(tmp+1,tmp+m+1)-tmp-1; memset(sum,0,sizeof(sum)); for(int i=1;i<=n;i++) { l[i].l=lower_bound(tmp+1,tmp+m+1,l[i].l)-tmp; l[i].r=lower_bound(tmp+1,tmp+m+1,l[i].r)-tmp; for(int j=l[i].l;j<=l[i].r;j++) sum[j][l[i].l]++; } sort(l+1,l+n+1,cmp); for(int i=1;i<=m;i++) for(int j=1;j<=i;j++) sum[i][j]+=sum[i][j-1]; int ma=1,p=1,ans=0; memset(dp,0,sizeof(dp)); for(int i=1;i<=m;i++) { if(sum[i][i]>=3) dp[i]=sum[i][i]; while(l[p].r<i) { ma=max(ma,l[p].l); p++; } for(int j=ma;j<i;j++) { if(sum[i][i]-sum[i][j]>=3) dp[i]=max(dp[i],dp[j]+sum[i][i]-sum[i][j]); else dp[i]=max(dp[i],dp[j]); } ans=max(ans,dp[i]); } printf("Case #%d: %d\n",cas,ans); } return 0; }
最后感慨一下:简直日了g了。。。膜拜大佬们错的题意居然都过了。。。orz不对是or2。