1. 程式人生 > >ACM-ICPC 2018 徐州賽區網路預賽 K. Morgana Net (矩陣快速冪)

ACM-ICPC 2018 徐州賽區網路預賽 K. Morgana Net (矩陣快速冪)

題意

給你一個n*n的矩陣A,和一個m*m的矩陣B(m%2==1)

B是卷積核,讓你用B對A做t次卷積運算,並且對於A中的每一個元素計算出來的值要模2,所以A最後會是一個01矩陣。

問你經過t此後,A中有多少個元素=1

1<=t<=1e9,1<=n<=8,1<=m<=n

解析:

這道題按理來說就是一道很普通的矩陣快速冪的題目,但是比賽裡只有95個做出來...而且計蒜客還把這道題難度標成3星...

這個導致我以為是什麼數學公式,就直接搜了卷積轉換成矩陣乘法的公式,嗯...確實3星..要用到Toeplitz矩陣...

然後搜了題解...矩陣快速冪,構造矩陣...?????

這道題之所以能用矩陣快速冪是因為這個n實在太小了..你把每一個元素拿出來也才64個元素...

那麼做法就是把A矩陣變成一個1*(n*n)的一維向量,然後構造一個(n*n)*(n*n)的輔助矩陣

我們觀察到對於A中的每一個元素,每一次卷積運算,所要求乘積的值的位置是固定的,那麼我們就提前預處理出

對於A中的每一個元素求出參與該元素的卷積運算的對應元素的位置。

這樣複雜度是O(T*n^6*logt),因為這裡有多組資料T=100,所以可能會有卡常,需要用biset優化一下

最終的複雜度就是O(T*n^4*logt)

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <bitset>
using namespace std;

typedef long long ll;
const int MOD = 2;
const int MAXN = 40000;

typedef struct {

    bitset<80> m[80];
    int sizx,sizy;

}Matrix;
int n,m;
Matrix cb;
inline Matrix Mul(Matrix a, Matrix b)
{
    Matrix c;

    c.sizx=a.sizx;
    c.sizy=b.sizy;
    cb.sizy=b.sizx;
    cb.sizx=b.sizy;
    for(int i=0;i<b.sizy;i++)
    {
        cb.m[i].reset();
        for(int j=0;j<b.sizx;j++)
        {
            cb.m[i][j]=b.m[j][i];
        }
    }
    for (int i = 0; i < a.sizx; i++)
    {
        c.m[i].reset();
        for (int j = 0; j < b.sizy; j++)
        {
            bitset<80> tmp=(a.m[i]&cb.m[j]);
            c.m[i][j]=tmp.count()&1;
        }
    }
    return c;
}

inline Matrix fastm(Matrix a, ll num)
{
    Matrix res;
    for(int i=0;i<a.sizx;i++) res.m[i].reset();
    res.sizx=a.sizx;
    res.sizy=a.sizy;
    for(int i=0;i<a.sizx;i++)
        res.m[i][i]=1;
    while (num)
    {
        if (num & 1)
            res = Mul(res, a);
        num >>= 1;
        a = Mul(a, a);
    }
    return res;
}


Matrix a,b,c;
int main()
{
    int cas;
    scanf("%d",&cas);
    while(cas--)
    {

        int t;
        scanf("%d%d%d",&n,&m,&t);
        a.sizx=1;a.sizy=n*n;
        a.m[0].reset();
        for(int i=0;i<n*n;i++)
        {
            int tmp;
            scanf("%d",&tmp);
            a.m[0][i]=tmp&1;
        }

        for(int i=0;i<m;i++)
        {
            for(int j=0;j<m;j++)
            {
                int tmp;
                scanf("%d",&tmp);
                b.m[i][j]=tmp&1;
            }
        }

        c.sizx=c.sizy=n*n;
        int num=0;
        int in=0;
        m=m>>1;
        for(int i=0;i<n*n;i++) c.m[i].reset();
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                for(int p=i-m;p<=i+m;p++)
                {
                    for(int q=j-m;q<=j+m;q++)
                    {
                        in=p*n+q;
                        if(p>=0&&p<n&&q>=0&&q<n)
                        {
                            c.m[in][num]=(b.m[p-i+m][q-j+m]);
                        }

                    }

                }
                num++;
            }

        }
        c=fastm(c,t);
        a=Mul(a,c);

        printf("%d\n",a.m[0].count());
    }


}