题目1550:分糖果
第二种是将把所有的人看成图中的一个点,两个相邻的人如果s的值不一样的话可以从大的往小的连一条边,可以很明显的看出,这些人与这些边构成了有向无环图。。
这场比赛的题目很水。。。
准确来说是这个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;
}
第二种是将把所有的人看成图中的一个点,两个相邻的人如果s的值不一样的话可以从大的往小的连一条边,可以很明显的看出,这些人与这些边构成了有向无环图。。
然后直接在根节点开始走。每次加一。如果是两边都是小于本身就选取最小的邻节点加一。
这种情况下是不可能有多余的搜索。每个节点最多扫描两次。时间复杂度为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;
}