1 条题解

  • 0
    @ 2025-8-24 22:08:34

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Social_Zhao
    悲しくって 泣いてるわけじゃあない

    搬运于2025-08-24 22:08:34,当前版本为作者最后更新于2019-03-02 19:03:21,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    Updated at 2019/3/2/21:56,重新发表

    (实际上是发表后几小时,有一位大佬
    https://www.luogu.org/space/show?uid=79067
    权))

    看了诸位大佬的题解,蒟蒻一脸懵逼

    难道我写出了本题最短代码???

    毕竟是自己YY出的野递推式

    • 首先来看张表:(没错这就是我用暴力打出来的表的一部分,下标从1开始)

    1 ······
    3 4 ······
    6 10 11
    10 20 25 26
    15 35 50 56 57
    ······
    • 请自行脑补行号、列号(逃

    • 于是精通找规律的本蒟蒻看出一个递推公式来

    • 再说这个公式前,先举几个栗子。

    • 对于第2行2列的数:4,它其实是它左上角的数1加上它上方的数1再加上它的行号2
    • 对于第2行3列的数:10,它其实是它左上角的数3加上它上方的数4再加上它的行号3
    • 对于第5行5列的数:57,它其实是它左上角的数26加上它上方的数26再加上它的行号5
    • 特殊情况——对于1行m列的数1,它其实是它左上角的数(初始化为0)加上它上方的数(初始化为0)再加上它的行号1
    • 以及——对于n行1列的数1,它其实是它左上角的数(初始化为0)加上它上方的数(初始化为0)再加上它的行号1
    • 我想这五个例子应该足以说明问题了吧?下面就是我的递推式:

    • ans[i][j]=ans[i1][j1]+ans[i1][j]+ians[i][j]=ans[i-1][j-1]+ans[i-1][j]+i


    下面是推导过程,看不懂可以自行跳过


    为毛是这样的 ?

    感谢@dou_bao大佬的解释。(已获得原作者授权)

    我们需要三张表

    1.帕斯卡三角形(即杨辉三角)(数组ff

    1
    1 1 0 0 0 0 0 0
    2 1
    3 1
    4 6 4 1
    5 10 5 1
    6 15 20 15 6 1
    • 首先,我们需要知道C(x,y)C(x,y)等于帕斯卡三角形第y+1y+1行第x+1x+1个数。不知道的回家洗洗睡吧,我就不证明了

    • 所以从C(1,y)C(1,y)C(i,y)C(i,y)就是第y+1y+1行第11i+1i+1个的数之和。

    • 所以题中所求的可以表示为

    for(int i=1;i<=x;i++)
        for(int j=2;j<=y;j++)
            ans+=f[i][j];
    
    • 不超时个鬼,所以要压缩

    • 所以第二张表

    2.帕斯卡三角形的前缀和(横着的)(不包括每行第一个数1)(数组gg

    | 1 | 1 | 1 | 1 | 1 | 1 | | :----: | :----: | :----: | :----: | :----: | :----: | :----: | :----: | | 2 | 3 | 3 | 3 | 3 | 3 | | 3 | 6 | 7 | 7 | 7 | 7 | | 4 | 10 | 14 | 15 | 15 | 15 | | 5 | 15 | 25 | 30 | 31 | 31 | | 6 | 21 | 41 | 56 | 62 | 63 |

    • 一个矩阵变成一行了。

    • 因为f[i][j]=f[i1][j]+f[i1][j1];f[i][j]=f[i-1][j]+f[i-1][j-1];

    • 所以g[i][j]g[i][j]就等于g[i1][j]+g[i1][j1]+1g[i-1][j]+g[i-1][j-1]+1(把g[i][j]=sum(f[1]g[i][j]=sum(f[1] to f[i])f[i])展开就可以得到,实在无法理解可以在表中找规律)

    • 俗话说的好,做事要干净,不给别人留后路

    • 所以第三张表

    3.帕斯卡三角形横着的前缀和的前缀和(竖着的)(数组ansans

    | 1 | 1 | 1 | 1 | 1 | 1 | | :----: | :----: | :----: | :----: | :----: | :----: | :----: | :----: | | 3 | 4 | 4 | 4 | 4 | 4 | | 6 | 10 | 11 | 11 | 11 | 11 | | 10 | 20 | 25 | 26 | 26 | 26 | | 15 | 35 | 50 | 56 | 57 | 57 | | 21 | 56 | 91 | 112 | 119 | 120 |

    • 是不是和第一张表一模一样?
    • 那么很明显 ans[i][j]=ans[i1][j]+g[i][j]ans[i][j]=ans[i-1][j]+g[i][j]
    • 又因为之前的g[i][j]=g[i1][j]+g[i1][j1]+1g[i][j]=g[i-1][j]+g[i-1][j-1]+1
    • 所以ans[i][j]=ans[i1]+g[i1][j]+g[i1][j1]+1ans[i][j]=ans[i-1]+g[i-1][j]+g[i-1][j-1]+1
    • 再不断地拆g[i1][j]g[i-1][j]
    • 就得到了ans[i][j]=ans[i1][j]+g[0ans[i][j]=ans[i-1][j]+g[0 to i1][j1]+ii-1][j-1]+i
    • 然后又因为h的定义,所以ans[i][j]=g[0ans[i][j]=g[0 to i][j]i][j]
    • 那么可以变形为:
    • ans[i][j]=ans[i1][j]+ans[i1][j1]+ians[i][j]=ans[i-1][j]+ans[i-1][j-1]+i

    • 就是这样
    • 题解写的丑,dalao勿喷。

    证毕。


    于是......这就是我的只有15行的代码了(未压行):

    #include<iostream>
    using namespace std;
    int ans[1005][1005],q,n,m;
    int main() {
    	for(int i=1;i<=1000;i++)
    	for(int j=1;j<=1000;j++) {
    		ans[i][j]=(ans[i-1][j-1]+ans[i-1][j]+i)%19260817;
    	}
    	cin>>q;
    	while(q--) {
    		cin>>n>>m;
    		cout<<ans[m][n]<<endl;
    	}
    	return 0;
    }
    
    • 1

    信息

    ID
    4198
    时间
    1000ms
    内存
    125MiB
    难度
    3
    标签
    递交数
    0
    已通过
    0
    上传者