我先谔谔一波 /kk 我谔谔

看题第一眼:欸这不就是按题意递归嘛,,直接搞不就好了

3 min 后,重新看题

然后自己手玩了几个样例,噢,递归太多了,铁定会 T 啊......

然后,作为一个从没写过记忆化搜索的蒟蒻,苦苦思索了十几分钟。。。。。。

然后忽然想到可以用一个数组记录每一次的状态,然后如果递归到重复的数字直接返回记录的值,这就叫记忆化搜索!

我竟然就这样把记忆化搜索给 yy 出来了......

然后就是无尽的采坑。。。


首先,就是开了一个叫 \(\mathtt{mem}\) 的三维数组,然后每次递归就查询对应的位置,如果有值就返回,否则再按题目的意思一个一个去把 \(\mathtt{mem}\) 数组赋值。写出来大概就是这个样子:

long long w(long long a,long long b,long long c)
{
if(mem[a][b][c]!=0) return mem[a][b][c];
if(a<=0||b<=0||c<=0) return 1;
else if(a>20||b>20||c>20) mem[a][b][c]=w(20,20,20);
else if(a<b&&b<c) mem[a][b][c]=w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c);
else mem[a][b][c]=w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1);
}

然而又 WA 又 T 的,心酸。。。

然后突然发现数据范围: \([−9223372036854775808,9223372036854775807]\)

那递归开头就去判断如果下标是一个很大的负数咋办???岂不是会出现奇奇怪怪的错误???

所以,可以将函数里的第一行和第二行调换一下,这样就先去判断是否是负数了

long long w(long long a,long long b,long long c)
{
if(a<=0||b<=0||c<=0) return 1;
if(mem[a][b][c]!=0) return mem[a][b][c];
else if(a>20||b>20||c>20) mem[a][b][c]=w(20,20,20);
else if(a<b&&b<c) mem[a][b][c]=w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c);
else mem[a][b][c]=w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1);
}

然而又 WA 了!!!咋回事啊???

于是经过长达十几分钟的手玩数据,发现最后不会返回答案!!!所以在函数最后返回这个值就好了......

long long w(long long a,long long b,long long c)
{
if(a<=0||b<=0||c<=0) return 1;
else if(mem[a][b][c]!=0) return mem[a][b][c];
else if(a>20||b>20||c>20) mem[a][b][c]=w(20,20,20);
else if(a<b&&b<c) mem[a][b][c]=w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c);
else mem[a][b][c]=w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1);
return mem[a][b][c];
}

这下呢???20分!!!

然后又是十几分钟的手玩数据,突然发现 \(\mathtt{mem}\) 数组的值每次不会被清空。换而言之,在以后我们每次都在使用上次记忆的值。

既然如此,每次把 \(\mathtt{mem}\) 数组清零不久好了???

这个时候主函数就被改成了这样

int main()
{
int a,b,c; while(scanf("%d%d%d",&a,&b,&c)&&(a!=-1)&&(b!=-1)&&(c!=-1))
printf("w(%d, %d, %d) = %d\n",a,b,c,w(a,b,c)); return 0;
}

还是不行!!!为啥???不难发现,若 \(a,b,c\) 的值过大,记忆数组存不下!!!

如何解决呢?考虑当 \(>20\) 时,并不会对 \(a,b,c\) 本身进行操作,换而言之,\(a=114514\) 和 \(a=21\) 本质是一样的!!!

int main()
{
int a,b,c; while(scanf("%d%d%d",&a,&b,&c)&&(a!=-1)&&(b!=-1)&&(c!=-1))
{
memset(mem,0,sizeof(0));
printf("w(%d, %d, %d) = ",a,b,c);
//注意,下面的 a,b,c 要被修改,所以得先行输出
if(a>20) a=21;
if(b>20) b=21;
if(c>20) c=21;
printf("%d\n",w(a,b,c));
} return 0;
}

还是过不了!!!我要被搞疯了

最后还是把错误 yy 了出来, while 里的判断条件会使得如果 \(a,b,c\) 有一个是负数(不是 \(-1\) )就会结束......

最终 \(\mathtt{AC}\) 代码......

#include <iostream>
#include <stdio.h>
#include <string.h> using namespace std; long long mem[101][101][101]={}; long long w(long long a,long long b,long long c)
{
if(a<=0||b<=0||c<=0) return 1;
else if(mem[a][b][c]!=0) return mem[a][b][c];
else if(a>20||b>20||c>20) mem[a][b][c]=w(20,20,20);
else if(a<b&&b<c) mem[a][b][c]=w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c);
else mem[a][b][c]=w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1);
return mem[a][b][c];
} int main()
{
long long a,b,c; while(scanf("%lld%lld%lld",&a,&b,&c)==3)
{
if((a==-1)&&(b==-1)&&(c==-1)) break;
memset(mem,0,sizeof(0));
printf("w(%lld, %lld, %lld) = ",a,b,c);
if(a>20) a=21;
if(b>20) b=21;
if(c>20) c=21;
printf("%lld\n",w(a,b,c));
} return 0;
}

所以说我仍然谔谔

【做题笔记】洛谷P1464 Function的更多相关文章

  1. (水题)洛谷 - P1464 - Function

    https://www.luogu.org/problemnew/show/P1464 #include<bits/stdc++.h> using namespace std; #defi ...

  2. 洛谷P1464 Function  HDU P1579 Function Run Fun

    洛谷P1464 Function HDU P1579 Function Run Fun 题目描述 对于一个递归函数w(a,b,c) 如果a≤0 or b≤0 or c≤0就返回值11. 如果a> ...

  3. 洛谷 P1464 Function【记忆化搜索】

    题目链接 题目描述 对于一个递归函数w(a,b,c) 如果a<=0 or b<=0 or c<=0就返回值1. 如果a>20 or b>20 or c>20就返回w ...

  4. 洛谷 P1464 Function【动态规划(递推)/记忆化搜索(递归)】

    题目描述 对于一个递归函数w(a,b,c) 如果a<=0 or b<=0 or c<=0就返回值1. 如果a>20 or b>20 or c>20就返回w(20,2 ...

  5. 洛谷 P1464 Function

    题目描述 对于一个递归函数w(a,b,c) 如果a<=0 or b<=0 or c<=0就返回值1. 如果a>20 or b>20 or c>20就返回w(20,2 ...

  6. 洛谷P1464 Function

    对于一个递归函数w(a,b,c)w(a,b,c) 如果a \le 0a≤0 or b \le 0b≤0 or c \le 0c≤0就返回值11. 如果a>20a>20 or b>20 ...

  7. 洛谷 P1464 Function(简单记忆化)

    嗯... 让一切从水开始吧... 水过初赛,但愿复赛能够接着水过... 这道题不记忆化会tle,所以用空间换时间,将每次的答案(只有20*20*20个)存下来,如果之前已经求过,就不需要重复求了... ...

  8. java实现 洛谷 P1464 Function

    import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.S ...

  9. C语言程序设计做题笔记之C语言基础知识(下)

    C 语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行 事.并且C是相当灵活的,用于执行计算机程序能完成的 ...

随机推荐

  1. EOFError: Compressed file ended before the end-of-stream marker was reached解决办法(在Windows下查看已下载的MNIST数据文件)

    出现这个问题的原因是因为文件下载到一半就中断了,解决办法是删除datasets中下载到一半的数据包. 下面以我遇到的问题为例: 我下载数据下载到最后一个包就没有反应了,于是我强制终止了运行,可能是因为 ...

  2. Git和TortoiseGit

    1.简介 Git是一个开源的分布式版本控制系统,用于敏捷高效的处理任何或大或小的项目.它采用了分布式版本库的方式,不必服务器端软件支持. 2.Git和Svn的区别 1.Git 是分布式的,SVN 不是 ...

  3. source insight增加tab标签页的方法之sihook

    1.效果如下 2.方法见如下博客 http://www.cnblogs.com/Red_angelX/archive/2013/01/23/2873603.html

  4. maven - 一键删除maven仓库无效jar包工具

    背景 在进行maven开发时,往往需要下载大量jar包,而由于网络不稳定等其他因素可能导致jar未下载完毕,然后保留了lastUpdated文件,导致无法更新失效的jar包. 现在提供个bat脚本,只 ...

  5. arm9特点

    ARM9主要特点 ARM 处理器凭借它的低功耗.高性能等特点,被广泛应用于个人通信等嵌入式领域,而ARM7 也曾在中低端手持设备中占据了一席之地.然而,ARM7 的处理性能逐渐无法满足人们日益增长的高 ...

  6. redis的linux安装

    1.下载安装包 [root@localhost opt]# yum install wget [root@localhost opt]# wget http://download.redis.io/r ...

  7. 四、CentOS 7安装Oracle JDK

    CentOS 7安装Oracle JDK,查看Linux是否自带的JDK,如有openJDK,则卸载  CentOS7.1 JDK安装 1.卸载自带OPENJDK    用 java -version ...

  8. python:运行command

    #!/usr/bin/python# -*- coding:utf-8 -*- import os os.system('cocos jscompile -s ./dir1 -d ./dir2')

  9. Eclipse导入工程Some projects cannot be imported because they already exist in the workspace

    记录一下本次出错原因,以及解决方法 错误原因: 第一次导入后,删除工程,没有没有勾选Delete project contents on disk(cannot be undone) 解决方法: 1 ...

  10. 洛谷P1583 魔法照片

    https://www.luogu.org/problem/P1583 话不多说,其实就是模拟,然后,各种繁琐 #include<bits/stdc++.h> using namespac ...