第一篇博客 CF 283B Cow Program

小郭同学老和我说写博客多么多么好,近期又发现了ronnoc的博客,忽然发现如果把大学做ACM的经历都记下来,也是挺好的一件事,说不定有一天我的博客也能帮助到刚刚接触ACM的新人。有朝一日如果我也能变成神牛,回头看看自己成长的过程也是挺好的一件事。加上今天一下午一直在一个题上TLE,最后终于调通了,所以我愉快的决定从今天起开始写博客。既然是计算机方面的,那必须是CSDN啊,果断开通之。

那第一篇就记一下我今天被卡了一下午TLE的题目吧。

CF 283B  http://codeforces.com/problemset/problem/283/B   Cow Program

题意不解释,相信特意搜这些关键词的人都是看过题的。

题目怎么解???

最傻叉的办法,就是模拟,显然会超时。我们对题目中数据范围要特别注意,n20左右的一般是2^n复杂度,n如果是1000左右,那估计就是n^2的复杂度,如果出现100000,那么估计是O(n)或者O(nlogn)

回到这个题,很明显只有第一个数是变的,那么后面不变的数,就可以直接把他们的结果求出来了,即如果在i这一点,需要操作是+(或者是-,那么这一状态走到结束需要的费用是多少(就是y要加多少),或者说这个状态一直会循环。一共2*n-1)个状态,第一点为减的状态不会出现,自己想一想就知道了。那么就一次对各个点dfs,遇到搜过的点直接返回结果,复杂度O(n).

于是乎我的代码产生了

#include "iostream"
#include "cstdio"
#include "cstring"
#include "cmath"
#include "stdlib.h"
#include "algorithm"
using namespace std;
long long ans[200010][2],a[200010];
bool visit[200010][2];
int T;
long long dfs(int m,int n)
{
    if(visit[m][n]==true)
        return -1;
    visit[m][n]=true;
    long long temp;
    if(n==0)
    {
        if(a[m]+m>T)
            ans[m][n]=a[m];
        else
        {
            if(ans[m+a[m]][1]!=0)
                temp=ans[m+a[m]][1];
            else
                temp=dfs(a[m]+m,1);
            if(temp==-1)
                ans[m][n]=-1;
            else
                ans[m][n]=a[m]+temp;
        }
    }
    else
    {
        if(m-a[m]<=0)
            ans[m][n]=a[m];
        else
        {
            if(ans[m-a[m]][0]!=0)
                temp=ans[m-a[m]][0];
            else
                temp=dfs(m-a[m],0);
            if(temp==-1)
                ans[m][n]=-1;
            else
                ans[m][n]=a[m]+temp;
        }
    }
    return ans[m][n];
}
int main()
{
    scanf("%d",&T);
    for(int i=2; i<=T; i++)
        scanf("%lld",&a[i]);
    memset(ans,0,sizeof(ans));
    ans[1][0]=-1;
    for(int i=2; i<=T; i++)
        for(int j=0; j<2; j++)
            if(ans[i][j]==0)
            {
                memset(visit,false,sizeof(visit));
                visit[1][0]=true;
                dfs(i,j);
            }
    for(int i=2; i<=T; i++)
    {
        if(ans[i][1]==-1)
        printf("-1\n");
        else
        printf("%lld\n",i-1+ans[i][1]);
    }
}


跑到第九组数据果断TLE了,我也不知道为什么。后来读来读题目,不建议用%lld,应为我用linux编的,所以用了lld,改成I64d,还是TLEa数组改成int的,还是TLE,这些都是小打小闹,更本不管用。

后来发现其实并不是所有的状态都要求出来,有些是用不到的,所以改成了把用到的求出来,也就是把dfs放到输出那里,只求对我有用的。可结果还是TLE了。

后来我觉的我的dfs写的太丑了,不要把这一步是加还是减分开搞,用一个叫mark的数组判断是加还是减,然后用位运算去改变状态,代码的改动是这样的:

mark[2]= {1,-1};
next=mark[n]*a[m]+m;//这样加还是减就不用判断了
dfs(next,1^n);//这里用亦或


当然这三行不是连着的,我只是把我觉的重要的地方找出来,并且我不是每次都初始化visit数组,而是初始化一次。然后代码就特别短,而且速度飞快,终于AC了。最终我也没弄清楚到底是哪一步把效率提高的,不想去折腾它了,什么时候有兴致了再看吧。

贴代码

#include "iostream"
#include "cstdio"
#include "cstring"
#include "cmath"
#include "stdlib.h"
#include "algorithm"
using namespace std;
long long ans[200010][2];
int a[200010],mark[2]= {1,-1},T;
bool visit[200010][2];
long long dfs(int m,int n)
{
    if(visit[m][n]==true)
        return ans[m][n];
    visit[m][n]=true;
    int next=mark[n]*a[m]+m;
    if(next>T||next<=0)
        ans[m][n]=a[m];
    else
    {
        long long temp=dfs(next,1^n);
        if(temp==-1)
            ans[m][n]=-1;
        else
            ans[m][n]=(long long)a[m]+temp;
    }
    return ans[m][n];
}
int main()
{
    scanf("%d",&T);
    for(int i=2; i<=T; i++)
        scanf("%d",&a[i]);
    memset(ans,-1,sizeof(ans));
    memset(visit,false,sizeof(visit));
    visit[1][0]=true;
    for(int i=2; i<=T; i++)
    {
        if(!visit[i][1])
            dfs(i,1);
        if(ans[i][1]==-1)
            printf("-1\n");
        else
            printf("%I64d\n",i-1+ans[i][1]);
    }
}


水平有限,众神轻喷。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值