【JZOJ4901】【NOIP2016提高A组集训第18场11.17】矩阵

来源:互联网 发布:java 方法命名规范 编辑:程序博客网 时间:2024/06/02 06:31

题目描述

他是一名普通的农电工,他以一颗无私奉献的爱岗敬业之心,刻苦钻研业务,以娴熟的技术、热情周到的服务赢得了广大客户的尊敬和赞美。他就是老百姓称为“李电”的李春来。
众所周知,李电很喜欢YY。一天,他又YY 了奇怪的东西。他假设他自己成了神,然后他说:“出来吧,矩阵。”然后一个N _M 的矩阵从天而降。他为了不要让矩阵太大而使得自己眼花缭乱,所以他将M 固定在了3。但是,一天之后,他想继续他之前的YY,继续玩他的矩阵,但是他的记忆力太差了,所以他不记得他原来的矩阵长得什么样,所幸的是他昨天记录下了矩阵中每行每列的和,还有矩阵的每项都是非负整数。所以他想知道满足这样条件的矩阵总共有多少种。

数据范围

对于20% 的数据,满足n <= 3,0<=a,b,c,s_i<=10
对于40% 的数据,满足n<=10,0<=a,b,c,s_i<=20
对于60% 的数据,满足n<=40,0<=a,b,c,s_i<=40
对于100% 的数据,满足n<=125,0<=a,b,c,s_i<=125

=w=

设f[i][j][k]表示,第i行中第一列填个j,第二列中填个k。
f[i][j][k]=f[i1][ja][kb]并且满足a+b<=s[i]
然后咧,这个是O(n5)的。
考虑一个第i行:
这里写图片描述
根据转移方程,f[i][j][k]是由图中这个黑色的等腰直角三角形转移过来的。
那么考虑维护这个等腰直角三角形:
黑色等腰直角三角形=红色长方形-(黄色等腰直角三角形-青绿色等腰直角三角形)
显然矩形前缀和以及腰所在的直线在x轴的等腰直角三角形前缀和容易维护。


时间复杂度为O(n3)

代码

Const        maxn=135;        mo=100000000000000000;Var        n,i,j,k,l,o:longint;        m1,m2,m3:longint;        f:array[0..maxn,0..maxn,0..maxn] of int64;        a,sum:array[0..maxn] of longint;Function max(a,b:longint):longint;begin        if (a>b) then exit(a);        exit(b);end;Begin        assign(input,'mat.in');reset(input);        assign(output,'mat.out');rewrite(output);        readlN(n);        readlN(m1,m2,m3);        for i:=1 to n do        begin                read(a[i]);                sum[i]:=sum[i-1]+a[i];        end;        if (sum[n]>m1+m2+m3) or (sum[n]<m1+m2+m3) then        begin                writeln(0);        end        else        begin                f[0][0][0]:=1;                for i:=1 to n do                begin                        for j:=0 to m1 do                                for k:=0 to m2 do                                begin                                        if (sum[i]<j+k) then break;                                        if (sum[i]-j-k>m3) then continue;                                        for l:=0 to j do                                                for o:=max(0,j+k-a[i]-l) to k do                                                begin                                                        if (sum[i]-j-k>=sum[i-1]-l-o) then                                                        begin                                                                f[i][j][k]:=(f[i][j][k]+f[i-1][l][o]) mod mo;                                                        end;                                                end;                                end;                end;                writeln(f[n][m1][m2]);        end;        close(input);close(output);End.

=o=

当一个f[i]从f[i-1]转移过来时,可以画个平面直角坐标系,看看要维护的是什么。
有必要的话,建立空间直角坐标系。

0 0
原创粉丝点击