矩陣快速冪——max JZOJ(GMOJ)6309 完全揹包

矩陣快速冪——max JZOJ(GMOJ)6309 完全揹包

在這裏插入圖片描述

前置知識

矩陣快速冪 是可以自己新定義運算的, 只要滿足結合律即可 最近心血來潮, 搞出了一個叫 "矩陣max法"的東西(我瞎編的名字) 以下是運算規則

C=A   max   BCi,j=MAXk=1n{Ai,k+Bk,j}C=A \: \; max \: \; B \\C_{i,j}=MAX^n_{k=1}\left\{ A_{i,k}+B_{k,j}\right\}

關於結合律的證明
D=B  max  CE=A  max  D=A  max  (B  max  C)D=B\;max\;C \\ E=A \;max\; D=A \;max\;(B\;max\;C)

Ei,j=Maxk=1n{Ai,k+Dk,j}=Maxk=1n{Ai,k+MAXl=1n{Bk,l+Cl,j}}=Maxk=1n{MAXl=1n{Ai,k+Bk,l+Cl,j}}=Maxk=1n{MAXl=1n{Ai,k+Bk,l}+Cl,j}E_{i,j}\\ =Max^n_{k=1}\left\{A_{i,k}+D_{k,j}\right\}\\ =Max^n_{k=1}\left\{A_{i,k}+MAX^n_{l=1}\left\{B_{k,l}+C_{l,j}\right\}\right\}\\ =Max^n_{k=1}\left\{MAX^n_{l=1}\left\{A_{i,k}+B_{k,l}+C_{l,j}\right\}\right\}\\ =Max^n_{k=1}\left\{MAX^n_{l=1}\left\{A_{i,k}+B_{k,l}\right\}+C_{l,j}\right\}
E=A  max  B  max  C=A  max  (B  max  C)E=A\;max\;B\;max\;C=A \;max\;(B\;max\;C)
其中max法單位矩陣如下
I=[0infinf...infinf0inf...infinfinf0infinfinfinf0]I=\begin{bmatrix}0 & -inf&-inf &...&-inf \\ -inf & 0&-inf&...&-inf\\ \vdots & &\ddots &&\vdots \\ -inf&-inf&\cdots&0&-inf\\ -inf&-inf&\cdots&-inf&0 \end{bmatrix} \quad
零矩陣就更加簡單了
O=[infinfinf...infinfinfinf...infinfinfinfinfinfinfinfinf]O=\begin{bmatrix}-inf & -inf&-inf &...&-inf \\ -inf & -inf&-inf&...&-inf\\ \vdots & &\ddots &&\vdots \\ -inf&-inf&\cdots&-inf&-inf\\ -inf&-inf&\cdots&-inf&-inf \end{bmatrix} \quad
有了這些,我們就可以快速冪了

代碼(我快速冪打的醜,不要亂Copy)


#include<cstdio>
#include<cstring>
using namespace std;
int maxa=0;
int a[1000010],b[1000010];
long long ans[110][110],f[110];
long long stm[110][110],dt[110][110];
inline long long max(long long x,long long y){return (x>y?x:y);}
void DB()
{
    int i,j,k;
    for(i=1;i<=maxa;i++)
    {
        for(j=1;j<=maxa;j++)
        {
            printf("%d,%d\n",i,j);
            for(k=1;k<=maxa;k++) printf("%lld ",ans[i][k]+ans[k][j]);
            printf("\n");
    //      printf("%d ",ans[i][j]);
        }
        printf("\n");
    }
    printf("\n");
}
void sqr()
{
    int i,j,k;
    memset(dt,250,sizeof(dt));
    for(i=1;i<=maxa;i++)
        for(j=1;j<=maxa;j++)
            for(k=1;k<=maxa;k++) dt[i][j]=max(dt[i][j],ans[i][k]+ans[k][j]);
//  DB();
    for(i=1;i<=maxa;i++)
        for(j=1;j<=maxa;j++) ans[i][j]=dt[i][j];
}
void mul()
{
    int i,j,k;
    memset(dt,250,sizeof(dt));
    for(i=1;i<=maxa;i++)
        for(j=1;j<=maxa;j++)
            for(k=1;k<=maxa;k++) dt[i][j]=max(dt[i][j],ans[i][k]+stm[k][j]);
    for(i=1;i<=maxa;i++)
        for(j=1;j<=maxa;j++) ans[i][j]=dt[i][j];
}
void qpow(long long x)
{
    int i;
    memset(ans,200,sizeof(ans));
    for(i=1;i<=maxa;i++) ans[i][i]=0;
//  for(i=1;i<=maxa;i++) ans[i][maxa]=f[i];
    for(i=0;(x>>i)>0;i++);i--;
    for(;i>=0;i--)
    {
        sqr();
        if((x>>i)&1) mul();
    }
}
int main()
{
    freopen("backpack.in","r",stdin);
    freopen("backpack.out","w",stdout);
    int n,i,j;long long m;
    scanf("%d%lld",&n,&m);
    for(i=1;i<=n;i++) scanf("%d%d\n",&a[i],&b[i]);
    for(i=1;i<=n;i++) if(maxa<a[i]+1) maxa=a[i]+1;
//  maxa++;
    memset(f,0,sizeof(f));
    for(i=1;i<=n;i++)
        for(j=a[i];j<=maxa;j++) f[j]=max(f[j],f[j-a[i]]+b[i]);
    memset(stm,250,sizeof(stm));
    for(i=2;i<=maxa;i++) stm[i][i-1]=0;
    for(i=1;i<=n;i++) stm[maxa-a[i]+1][maxa]=max(stm[maxa-a[i]+1][maxa],b[i]);
    if(m<maxa){printf("%d\n",f[m]);return 0;}
    qpow(m-maxa+1);
/*  for(i=1;i<=15;i++) printf("%lld\n",f[i]);
    for(i=1;i<=maxa;i++)
    {
        for(j=1;j<=maxa;j++)
            if(ans[i][j]>=0) printf("%3lld ",ans[i][j]);
            else printf("inf ");
        printf("\n");
    }*/
    long long outans=-9223372036854775807ll;
    for(i=2;i<=maxa;i++) outans=max(outans,f[i-1]+ans[i][maxa]);
    printf("%lld\n",outans);
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章