这场比赛的题目很水。。。
准确来说是这个oj上的测试数据很水。。
不过我就是贪它数据水我才做,嘻嘻!!
这道题我在比赛中是用贪心算法直接模拟过的。。
但是过了之后我很模糊。。。。
因为我可以想到测试数据让我的代码超时。。。。
最后居然还是90ms,无语。。。。
先说我的第一种想法:由题目可知。给一个糖果的状态是可以直接知道的,就是左右两边都打过他本身,
这里跟一个糖果是最划算的。。
然后一个糖果放完之后有同样的方法放需要两个糖果的状态。
一直模拟下去知道全部放完。。
复杂度最差的情况下可以是O(n*si)绝对超过了一秒
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<vector> #include<math.h> using namespace std; int a[100005]; int f[100005]; int var[100005]; int main() { int n,i,j; //Init(); while(~scanf("%d",&n)) { memset(f,0,sizeof(f)); for(i=1;i<=n;i++) { scanf("%d",&a[i]); } a[0] = a[n+1] = 100005; if(n==1) { printf("1\n"); continue; } int ans = 0,k = 0,c = 0; while(k<n) { c++; int r = 0; for(i=1;i<=n;i++) { if(f[i]==0 && (f[i+1]>0 || a[i]<=a[i+1]) && (f[i-1]>0 || a[i]<=a[i-1])) { var[r++] = i; k++; ans+=c; } } for(i=0;i<r;i++) f[var[i]] = c; } printf("%d\n",ans); } return 0; }
然后直接在根节点开始走。每次加一。如果是两边都是小于本身就选取最小的邻节点加一。
这种情况下是不可能有多余的搜索。每个节点最多扫描两次。时间复杂度为O(n)
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<vector> #include<math.h> using namespace std; int a[100005]; int f[100005]; //int max(int a,int b) void work(int i,int n) { f[i] = 1; int k = i; while(k>0 && a[k]<a[k-1]) { f[k-1] = max(f[k-1],f[k]+1); k--; } k = i; while(k<=n && a[k]<a[k+1]) { f[k+1] = max(f[k+1],f[k]+1); k++; } } int main() { int n,i,j; //Init(); while(~scanf("%d",&n)) { memset(f,0,sizeof(f)); for(i=1;i<=n;i++) { scanf("%d",&a[i]); } a[0] = a[n+1] = 100005; if(n==1) { printf("1\n"); continue; } int ans = 0,k = 0,c = 0; for(i=1;i<=n;i++) { if(a[i]<=a[i+1] && a[i]<=a[i-1]) { work(i,n); } } for(i=1;i<=n;i++) ans+=f[i]; printf("%d\n",ans); } return 0; }
九度oj 2014年王道论坛研究生机试练习赛(二) 第四题,布布扣,bubuko.com
原文:http://blog.csdn.net/min_lala/article/details/20712011