CSP第23次 202109-2 非零段划分 全网运行速度最快答案

CSP第23次 202109-2 非零段划分 C语言90分答案

第23次csp我是有去参加的,当时 第一题100分 第二题70分 第四题10分

网上很多满分答案时间复杂度都是O(n*logn)也达标了,运行时间在300ms左右。
我下面这段代码只有O(n)的时间复杂度,仅31ms,运行速度应该是全网最快的了。
但只有90分,实在找不到哪里出错了,希望有大佬可以指点一下。
在这里插入图片描述

#include <stdio.h>
int arr[500010]={0};//存储题目给的数组
int dp_change[10010]={0};//动态规划,p为几时非零段数量的变化,往后看就懂了
int main()
{
	int i,n,p,max_p=10000,out=0,count=0;
	scanf("%d",&n);
	for(i=1;i<=n;i++)//读入数组arr,并将相邻元素去重
    {
		scanf("%d",&arr[i]);
		if(arr[i-1]==arr[i])
            n--,i--;
    }
    for(i=1;i<=n;i++)//计算dp_change[]
    {
        if(arr[i]<arr[i-1]&&arr[i]<arr[i+1])//如果某个数比自身左右两边的数都小,那么当p等于自身的值+1时非零段会多一个,例如自身为1时22122
            dp_change[arr[i]+1]++;
        else if(arr[i]>arr[i-1]&&arr[i]>arr[i+1])//如果某个数比自身左右两边的数都大,那么当p等于自身的值+1时非零段会少一个,例如自身为1时00100
            dp_change[arr[i]+1]--;
    }
    if(n==0)
        out=count = 0;
    else
        out=count = ++dp_change[1];//dp_change[1]+1即p=0的非零段数量
    for(p=2;p<=max_p;p++)//递推出所有p的情况
    {
        count+=dp_change[p];
        count>out?out=count:0;
    }
	printf("%d",out);
	return 0;
 }

下面这段是70分运行超时,把这个版本也放出来吧

#include <stdio.h>
//70分,运行超时
int arr[500010];
int main()
{
	int i,j,n,p,max_p=10000,out=0;
	scanf("%d",&n);
	for(i=0;i<n;i++)
		scanf("%d",&arr[i]);

    for(p=0;p<=max_p;p++)
    {
        int need=1,count=0;
        for(i=0;i<n;i++)
        {
            if(need&&arr[i]>=p)
            {
                need=0;
                count++;
            }else if(arr[i]<p)
                need=1;
        }
        count>out?out=count:0;
    }

	printf("%d",out);
	return 0;
 }

下面这段是当时考csp的时候的代码,当时思维还是很不开窍的哈哈,还没开始学习算法
当时是想着通过拉大p的间距(多提交几个不同p加大间距),偷一下测试点漏洞,减少运行时间。不建议大家看下面这段了,笑一笑就好

#include <stdio.h>
//70分,运行超时
int main()
{
	int i,j,k,l;
	int n;
	int max=0,out=0;
	scanf("%d",&n);
	int arr[n+1];
	for(i=1;i<=n;i++)
	{
		scanf("%d",&arr[i]);
		if(arr[i]>max)max = arr[i];
	}
	if(n>500)
	for(k=1;k<max;k+=5)
	{
		int tmp[n+1];
		int count=0;
		for(i=1;i<=n;i++)
			if(arr[i]<k)
				tmp[i]=0;
			else
				tmp[i]=arr[i];	
		for(i=1;i<=n;i++)
		{
			if(tmp[i-1]==0||i==1)
			{
				for(j=i;j<=n;j++)
				{
					if(j==n||tmp[j+1]==0)
					{
						int ok=1;
						for(l=i;l<=j;l++)
						{
							if(tmp[l]<=0)
							{
								ok=0;
								break;
							}
						 } 
						 if(ok==1)
						 {
							count++;
							i=j+1;
//							printf("count++\n",count);
							break;
						 }
					}
				}
			}
		}
//		printf("k=%d out=%d\n",k,out);
		if(count>out)
			out=count;
	}
	else
	for(k=1;k<max;k+=2)
	{
		int tmp[n+1];
		int count=0;
		for(i=1;i<=n;i++)
			if(arr[i]<k)
				tmp[i]=0;
			else
				tmp[i]=arr[i];	
		for(i=1;i<=n;i++)
		{
			if(tmp[i-1]==0||i==1)
			{
				for(j=i;j<=n;j++)
				{
					if(j==n||tmp[j+1]==0)
					{
						int ok=1;
						for(l=i;l<=j;l++)
						{
							if(tmp[l]<=0)
							{
								ok=0;
								break;
							}
						 } 
						 if(ok==1)
						 {
							count++;
							i=j+1;
//							printf("count++\n",count);
							break;
						 }
					}
				}
			}
		}
//		printf("k=%d out=%d\n",k,out);
		if(count>out)
			out=count;
	}
	printf("%d",out);
	return 0;
 } 
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

琴kk

给我一点点鼓励吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值