初见这就是个水的递归,先考虑暴力
暴力代码如下
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL w(LL a,LL b,LL c){
if(a<=0||b<=0||c<=0) return 1;
else if(a>20||b>20||c>20) return w(20,20,20);
else if(a<b&&b<c) return w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c);
else return w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1);
}
int main(){
LL a,b,c;
while(scanf("%lld%lld%lld",&a,&b,&c)){
if(a==-1&&b==-1&&c==-1) break;
printf("w(%lld, %lld, %lld) = %lld\n",a,b,c,w(a,b,c));
}
return 0;
}
至此,一锤定音。
尘埃,已然落地......个鬼嘞!全超时。
题干告诉我们,a=b=c=15时会出问题,所以我们尝试输入。
然后就发现卡住了,动都不动。
我们转念一想,想到了尝试小一点的三个相同数字,发现
不难发现,n,n,n的答案恰好是2的n次方!
于是我们在w()里写一句特判:
现在我们能拿到20pts了,可喜可贺
为了避免函数重复处理大量相同的子问题,我们不妨声明一个三维数组记录每组a,b,c的结果。
也就是记忆化搜索。
详细内容我放在代码注释里,以下是完整AC代码。
#include<bits/stdc++.h>//万能头文件
using namespace std;
typedef long long LL;//可以用LL代替long long
LL rem[21][21][21];//函数内只处理1-20
LL w(LL,LL,LL);
int main(){
LL a,b,c;
memset(rem,-1,sizeof(rem));//初始化数组,赋值-1
while(scanf("%lld%lld%lld",&a,&b,&c)){
if(a==-1&&b==-1&&c==-1) break;//跳出循环
printf("w(%lld, %lld, %lld) = %lld\n",a,b,c,w(a,b,c));
}
return 0;
}
LL w(LL a,LL b,LL c){
if(a<=0||b<=0||c<=0) return 1;
else if(a>20||b>20||c>20) return w(20,20,20);
else if(rem[a][b][c]!=-1) return rem[a][b][c];//如果已经存过数据,直接返回
else if(a==b&&b==c) return rem[a][b][c]=1<<a;//特判,1>>a相当于pow(2,a)
else if(a<b&&b<c) return rem[a][b][c]=w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c);
return rem[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);
}