Delta Wave
题目链接:https://vjudge.net/problem/UVA-1478
题解
剧毒题目(其实思维挺简单的,就是......)
分析一下,发现它的模型就是卡特兰数的经典模型,只不过中间有点变化
这道题其实就是选偶数个位置让它们组成一个括号序列(上走是左括号,下走是右括号,没有被选的位置就是平着走)
所以它的答案就是:
其中Cat(k)为卡特兰数第k项
看了一下数据范围,咦?mod去哪儿了?
莫非是高精!(当场吐血)
还真是高精,n还小于等于10000,T小于等于20
那直接写组合数,高精除高精,岂不T飞。。。
还是先想一下怎么优化常数
我们把卡特兰数展开:
那么之前的答案就是:
考虑一下把相邻的两项做个比值(防止计算组合数时的阶乘预处理):
发现它们的比值竟然是长这样的:
所以我们就可以把高精除高精换成了高精乘低精+高精除低精
我们对于每个k只需要把上一项乘上(n-2k+1)*(n-2k+2)再除以k*(k+1)就可以啦
每算完一个值就把它累加到ans里面,这样就可以节省空间
写完运行,为什么一组10000就要跑1s???
突然发现自己忘了压位。。。
发现r的分母做多只有8位,而开long long可以存18位,所以我们可以压10位~~~
所以120ms就过了。。。
AC的代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const long long D=10000000000ll;
#define N 1005
#define LL long long
LL now[N],ans[N],tmp[N];
void jia(LL a[],int &lena,LL b[],int lenb)
{
memset(tmp,0,sizeof(tmp));
int len=min(max(lena,lenb),10),i;
for(i=1;i<=len;i++)
tmp[i]=a[i]+b[i];
for(i=1;i<=len;i++)
if(tmp[i]>=D){
tmp[i+1]+=1ll*tmp[i]/D;
tmp[i]%=D;
}
while(tmp[len+1]){
len++;
tmp[len+1]+=1ll*tmp[len]/D;
tmp[len]%=D;
}
memcpy(a,tmp,sizeof(tmp));
lena=len;
}
void cheng(LL a[],int &lena,int b)
{
memset(tmp,0,sizeof(tmp));
int len=lena,i;
for(i=1;i<=len;i++)
tmp[i]=1ll*a[i]*b;
for(i=1;i<=len;i++)
if(tmp[i]>=D){
tmp[i+1]+=1ll*tmp[i]/D;
tmp[i]%=D;
}
while(tmp[len+1]){
len++;
tmp[len+1]+=1ll*tmp[len]/D;
tmp[len]%=D;
}
memcpy(a,tmp,sizeof(tmp));
lena=len;
}
void chu(LL a[],int &lena,int b)
{
memset(tmp,0,sizeof(tmp));
int len=lena,i;
long long t=0;
for(i=len;i>=1;i--){
tmp[i]=1ll*(1ll*D*t+1ll*a[i])/b;
t=1ll*(1ll*D*t+1ll*a[i])%b;
}
while(!tmp[len])
len--;
memcpy(a,tmp,sizeof(tmp));
lena=len;
}
int main()
{
int lennow,lenans,k,n;
while(~scanf("%d",&n)){
memset(now,0,sizeof(now));
memset(ans,0,sizeof(ans));
memset(tmp,0,sizeof(tmp));
now[1]=1;lennow=1;lenans=1;
jia(ans,lenans,now,lennow);
for(k=1;2*k<=n;k++){
cheng(now,lennow,(n-2*k+1)*(n-2*k+2));
chu(now,lennow,k*(k+1));
jia(ans,lenans,now,lennow);
}
int flg=0,ff=0;
for(k=min(lenans,10);k>=1;k--){
if(ans[k])flg=1;
if(flg){
if(!ff)
printf("%lld",ans[k]%D);
else
printf("%010lld",ans[k]);
}
ff=1;
}
printf("\n");
}
}
过了样例就交,发现WA了,结果是输出的问题,输出时把每一位的数的前导零分别mod掉了。。。
结果调了我一个小时。。。