2017.1.12【初中部 】普及组模拟赛C组 幸运票 题解

原题:

http://172.16.0.132/junior/#contest/show/1360/2

题目描述:

给你一个数N(1<=N<=50),每张票有2N位,同时给你这2N位上的和S,如果这张票的前N位的和等于后N位的和,那我们称这张票是吉祥的,每一位可以取0-9
你的任务是计算吉祥票的总数

输入:

输入N和S,S是所以位上的和,假设S<=1000

输出:

输出吉祥票的总数

样例输入:

2 2

样例输出:

4

分析:

题目要求组成一个2*N的数,前N位的和等于后N位的和=S/2,首先考虑两个特殊情况:N为奇数,答案为0(2)S=0和S=18*N,答案为1。
另前N的数字和为S/2的方法数=后N位数字和为S/2的方法数,所以答案等于ANS^2,ANS表示N的数字和为S/2的方法数,现在的任务就是计算ANS,很容易想到用状态f[i,j]表示i个数和为j的方法,那么ANS=f[N,S/2],怎么计算f[i,j]呢?可以从“第i上的数字是多少?”这个问题得到递推方程式:
这里写图片描述
另f[i,j]具有对称性:f[i,j]=f[i,9*i-j],可以把效率提高一倍,并要用高精度;

实现:

uses math;
var
        f:array[1..50,1..450]of string;
        n,s,i,j,k:longint;
function jia(x,y:string):string;
var
        s:string;
        i,j:longint;
        a,b,c:array[0..256]of longint;
begin
        fillchar(a,sizeof(a),0);
        fillchar(b,sizeof(b),0);
        fillchar(c,sizeof(c),0);
        s:='';
        a[0]:=length(x);
        b[0]:=length(y);
        for i:=1 to a[0]do a[i]:=ord(x[a[0]-i+1])-48;
        for i:=1 to b[0]do b[i]:=ord(y[b[0]-i+1])-48;
        if a[0]>b[0] then
        begin
                for i:=1 to a[0]do
                begin
                        c[i]:=a[i]+b[i]+c[i];
                        c[i+1]:=c[i] div 10;
                        c[i]:=c[i] mod 10;
                end;
                c[0]:=a[0];
                if c[a[0]+1]<>0 then inc(c[0]);
        end
        else
        begin
                for i:=1 to b[0]do
                begin
                        c[i]:=a[i]+b[i]+c[i];
                        c[i+1]:=c[i] div 10;
                        c[i]:=c[i] mod 10;
                end;
                c[0]:=b[0];
                if c[b[0]+1]<>0 then inc(c[0]);
        end;
        for i:=1 to c[0]do s:=s+chr(c[c[0]-i+1]+48);
        exit(s);
end;
function cheng(x,y:string):string;
var
        s:string;
        i,j,t:longint;
        a,b,c:array[0..256]of longint;
begin
        fillchar(a,sizeof(a),0);
        fillchar(b,sizeof(b),0);
        fillchar(c,sizeof(c),0);
        a[0]:=length(x);
        b[0]:=length(y);
        s:='';
        for i:=1 to a[0]do a[i]:=ord(x[a[0]-i+1])-48;
        for i:=1 to b[0]do b[i]:=ord(y[b[0]-i+1])-48;
        for i:=1 to a[0]do
        begin
                t:=0;
                for j:=1 to b[0]do
                begin
                        c[i+j-1]:=t+a[i]*b[j]+c[i+j-1];
                        t:=c[i+j-1]div 10;
                        c[i+j-1]:=c[i+j-1]mod 10;
                end;
                c[i+j]:=t;
        end;
        c[0]:=a[0]+b[0];
        if c[a[0]+b[0]]=0 then dec(c[0]);
        for i:=1 to c[0]do s:=s+chr(c[c[0]-i+1]+48);
        exit(s);
end;
begin
        assign(input,'tickets.in');reset(input);
        assign(output,'tickets.out');rewrite(output);
        readln(n,s);
        s:=s div 2;
        for i:=1 to n do f[i,0]:='1';
        for i:=1 to 50 do
                for j:=1 to 450 do f[i,j]:='0';
        for i:=1 to n do
                for j:=0 to s do
                begin
                        if j>9*i then f[i,j]:='0'
                        else
                                if(i=1)and(j>=0)and(j<=9)then f[i,j]:='1'
                                else
                                    for k:=0 to min(9,j)dof[i,j]:=jia(f[i,j],f[i-1,j-k]);
                end;
        if(s=n*9)or(s=0)then writeln(1)
        else writeln(cheng(f[n,s],f[n,s]));
        close(input);close(output);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值