CQOI2008矩阵的个数
Posted yuzhe123
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CQOI2008矩阵的个数相关的知识,希望对你有一定的参考价值。
反正对今天是无言。。。
其实这道题就是DP,如果用暴搜,必爆。。。
它的思路是这样滴
我们可以发现,只要决定了第一列和第二列的数,第三列的数就已经是确定了
那么我们就只需要考虑第一二列的数就行
那么我们需要五层循环:1.i【1~n】,用来表示的是到第几行
2.j【0~c1】,用来表示第一列的总和
3.k【0~c2】,用来表示第二列的总和
4.x【0~min(j,a[i])】,用来表示第一列的取值,但是取值不能超过它的限制条件
5.y【0~min(k,a[i]-x)],用来表示第二列的取值,但是取值不能超过它的限制条件
在mlg大佬的帮助下,我成功地意识到滚动的重要性,主要是空间只给了60MB左右,易燃易爆炸?
其实我们可以发现,我们每一层的状态都是一层层推下来,那么的话,我们就可以发现,我们到达的这一层的状态只与上一层状态有关
所以一波滚动走起
对了忘记说动态方程了,其实到这里很明显,就是:
f[i&1][j][k]+=f[(i&1)^1][j-x][k-y],f[i&1][j][k]%=mod
代码献上:
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> using namespace std; typedef long long ll; ll n,c1,c2,c3; ll a[300]; ll f[2][150][150]; int main(){ scanf("%lld%lld%lld%lld",&n,&c1,&c2,&c3); ll sum=0; for(long i=1;i<=n;i++){ scanf("%lld",&a[i]); sum+=a[i];} if(sum!=c1+c2+c3) { printf("0"); return 0; } //特判一下,看看所给数据是否满足条件 f[0][0][0]=1; //初始化,注意 for(ll i=1;i<=n;i++) for(ll j=0;j<=c1;j++) for(ll k=0;k<=c2;k++){ f[i&1][j][k]=0; //记住这一个!!要在它 for(ll x=0;x<=min(j,a[i]);x++) for(ll y=0;y<=min(k,a[i]-x);y++) f[i&1][j][k]+=f[(i&1)^1][j-x][k-y],f[i&1][j][k]%=100000000000000000;} printf("%lld",f[n&1][c1][c2]); }
以上是关于CQOI2008矩阵的个数的主要内容,如果未能解决你的问题,请参考以下文章