zoukankan      html  css  js  c++  java
  • 【BZOJ-4547】小奇的集合 矩阵乘法 + 递推

    4547: Hdu5171 小奇的集合

    Time Limit: 2 Sec  Memory Limit: 256 MB
    Submit: 175  Solved: 85
    [Submit][Status][Discuss]

    Description

     有一个大小为n的可重集S,小奇每次操作可以加入一个数a+b(a,b均属于S),求k次操作后它可获得的S的和的最大

    值。(数据保证这个值为非负数)

    Input

    第一行有两个整数n,k表示初始元素数量和操作数,第二行包含n个整数表示初始时可重集的元素。

    对于100%的数据,有 n<=10^5,k<=10^9,|ai|<=10^5

    Output

    输出一个整数,表示和的最大值。答案对10000007取模。

    Sample Input

    2 2
    3 6

    Sample Output

    33

    HINT

    Source

    By Hzwer

    Solution

    很显然,每次操作都是取最大和次大相加,然后如此下去

    如此这样发现,显然是一个fib前缀和的问题,那么显然可以递推

    优化这个递推,显然可以矩阵乘法

    $egin{bmatrix}S[max]&  S[cmax]& Sum end{bmatrix}*(egin{bmatrix} 1& &1& &0\ 1& &0& &0\ 1& &1& &1 end{bmatrix})^{K}$

    其中S[max]表示最大,S[cmax]表示次大

    如果初始的次大<0先不断累加最大,到>=0为止,然后进行上述处理

    Code

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    using namespace std;
    int  read()
    {
        int x=0,f=1; char ch=getchar();
        while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    #define MAXN 100010 
    #define L 4
    #define sz 3
    #define p 10000007
    int N,K;
    int S[MAXN];
    int sum;
    struct MatNode{int a[L][L]; MatNode() {memset(a,0,sizeof(a));}}A,D;
    MatNode MatMul(MatNode X,MatNode Y)
    {
        MatNode C;
        for (int k=1; k<=sz; k++)
            for (int i=1; i<=sz; i++)
                for (int j=1; j<=sz; j++)        
                    if (X.a[i][k] && Y.a[k][j])
                        (C.a[i][j]+=(long long)X.a[i][k]*Y.a[k][j]%p)%=p;
        return C;
    }
    MatNode MatPow(MatNode x,int y)
    {
        MatNode re;
        for (int i=1; i<=sz; i++) re.a[i][i]=1;
        for (int i=y; i; i>>=1,x=MatMul(x,x))
            if (i&1) re=MatMul(re,x);
        return re;
    }
    void BuildMat()
    {
        A.a[1][1]=1; A.a[1][2]=1; A.a[1][3]=0;
        A.a[2][1]=1; A.a[2][2]=0; A.a[2][3]=0;
        A.a[3][1]=1; A.a[3][2]=1; A.a[3][3]=1;
        D.a[1][1]=S[1]; D.a[2][1]=S[2]; D.a[3][1]=sum;
    }
    bool cmp(int a,int b) {return a>b;}
    int main()
    {
        N=read(),K=read();
        for (int i=1; i<=N; i++) S[i]=read(),sum+=S[i],sum=(sum+p)%p;
        sort(S+1,S+N+1,cmp); 
        while (S[2]<0 && K>0)
            {
                S[2]=(S[2]+S[1])%p; K--;
                sum+=S[2]; sum=(sum+p)%p;
            }
        BuildMat();
        D=MatMul(MatPow(A,K),D);
        int ans=(D.a[3][1]+p)%p;
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    Ceph性能优化
    查看linux中的TCP连接数
    从 PC 卸载 Office
    VDI数据恢复
    xencenter迁移云主机方法
    深入解析UUID及其应用(转载)
    XenServer master主机的作用
    解决CentOS下可以ping通ip ping不通域名
    利用Powershell查询AD中账号属性
    创建进程的第二种方法,以后很多都用这个方法。
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5780488.html
Copyright © 2011-2022 走看看