[vijos1477] 跳動的水珠

給個洛谷網址吧qwq傳送門

這題先說80分做法吧(洛谷上70分)
顯然我們可以對於每一個時間構造一個矩陣表示變化情況,然後我們注意到,因爲li,j={3,7,9}l_{i,j}=\{3,7,9\},所以每63個時間是一個循環,那麼我們構造63個轉移矩陣,然後連乘起來,再快速冪優化,有點類似於沼澤鱷魚那道題

簡單放一下70分代碼

#include <bits/stdc++.h>
using namespace std;

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)

typedef long long ll;

const int N=70;

template<typename T> void read(T &x){
   x=0;int f=1;
   char c=getchar();
   for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
   for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
    x*=f;
}

int n,m,x,p,t;
int to[N][N],tot;
string l[N][N],s;
int sz;

struct matrix{
    int a[N][N];
    matrix(){memset(a,0,sizeof(a));}
    void build(){
        Rep(i,1,sz)a[i][i]=1;
    }
    void print(){
        Rep(i,1,sz)
            Rep(j,1,sz)printf("%d%c",a[i][j],j==sz?'\n':' ');
    }
    matrix operator * (const matrix &x)const {
        matrix res;
        Rep(i,1,sz)
            Rep(j,1,sz)
                Rep(k,1,sz)
                    res.a[i][j]=1ll*(res.a[i][j]+1ll*a[i][k]*x.a[k][j]%p)%p;
        return res;
    }
}A[N],B,ans;

matrix Qpow(matrix base,int ind){
    matrix res;
    res.build();
    while(ind){
        if(ind&1)res=res*base;
        base=base*base;
        ind>>=1;
    }
    return res;
}

void output(matrix A){
    Rep(i,1,n){
        int last=-1e9,tim=0;
        Rep(j,1,m){
            int pos=to[i][j];
            if(A.a[1][pos]==last)tim++;
            else{
                if(tim)printf("%d %d ",tim,last);
                last=A.a[1][pos];
                tim=1;
            }
        }
        if(tim)printf("%d %d\n",tim,last);
    }
}

int main()
{
    read(n),read(m),read(x),read(p),read(t);
    Rep(i,1,n)
        Rep(j,1,m){
            int len;
            read(len);
            cin>>s;
            Rep(k,1,63/len)l[i][j]+=s;
        }
    Rep(i,1,n)
        Rep(j,1,m)
            to[i][j]=++tot;
    sz=n*m+1;
    Rep(k,0,62){
        Rep(i,1,n)
            Rep(j,1,m)
                switch(l[i][j][k]){
                    case 'C':
                        A[k+1].a[to[i][j]][to[i][j]]=1;
                        A[k+1].a[sz][to[i][j]]=x;
                        break;
                    case 'U':
                        if(i>1)A[k+1].a[to[i][j]][to[i-1][j]]++;
                        break;
                    case 'D':
                        if(i<n)A[k+1].a[to[i][j]][to[i+1][j]]++;
                        break;
                    case 'L':
                        if(j>1)A[k+1].a[to[i][j]][to[i][j-1]]++;
                        break;
                    case 'R':
                        if(j<m)A[k+1].a[to[i][j]][to[i][j+1]]++;
                        break;
                }
        A[k+1].a[sz][sz]=1;
    }
    ans.a[1][sz]=1;
    if(t<=63){
        Rep(i,1,t)ans=ans*A[i];
        output(ans);
        return 0;
    }
    B.build();
    Rep(i,1,63)B=B*A[i];
    ans=ans*Qpow(B,t/63);
    Rep(i,1,t%63)ans=ans*A[i];
    output(ans);
    return 0;
}

建議先寫出70分做法,這樣對於思考滿分做法有很大幫助,而且滿分代碼只需要在70分代碼上簡單改動就可以了


接下來我們考慮滿分做法,我們考慮我們最開始設計的那些轉移矩陣,其實非常稀疏,除了1那一行以外每一行就一個數,那麼相應的引申出兩種解決方案,一個是用鏈表來存矩陣,好像大家都是這麼做的,但是我tcl,只能寫更弱的方法
我們發現,一些水珠經過一段時間去了哪裏我們是確定的,所以我們把原來的矩陣轉化成一個線性表,A.link[i]A.link[i]表示重新標號之後編號爲ii的點最後去了哪裏,那麼顯然在兩個"矩陣"AABB合併成一個新的"矩陣"的時候,C.link[i]=B.link[A.link[i]]C.link[i]=B.link[A.link[i]],這個還是挺好理解的吧qwq,那麼接下來考慮產生水的情況,我們用A.create[i]A.create[i]表示"矩陣"AA在這個時間內點ii處新產生了多少水,那麼我們考慮"矩陣"AA,BB合併成CC之後,ii點所含的水珠格式C.val[i]C.val[i],首先應該包含B.create[i]B.create[i],同時,對於所有B.link[j]=iB.link[j]=ijjC.val[i]C.val[i]應該還要包含A.val[j]A.val[j],因爲他從jj經過linklink的作用,到達了ii,那麼我們最後發現這個createcreate數組可以融入到valval中,也必須這樣,因爲當我們後面做快速冪的時候,是一下乘上表示一段的"矩陣",但是createcreate只能表示一個時間的情況。

所以如果你剛纔寫的是重載運算符的寫法,你只需要把重載乘號的地方改一下,建立"矩陣"的部分改一下,還有建立單位矩陣的方式改一下就好了

對於新的"矩陣"的"單位矩陣II",我們讓I.val[i]=0,I.link[i]=iI.val[i]=0,I.link[i]=i就可以了

#include <bits/stdc++.h>
using namespace std;

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)

typedef long long ll;

const int N=105;

template<typename T> void read(T &x){
   x=0;int f=1;
   char c=getchar();
   for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
   for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
    x*=f;
}

int n,m,x,p,t;
int to[N][N],tot;
string l[N][N],s;
int sz;

struct matrix{
    int link[N*N],val[N*N];
    matrix(){memset(link,0,sizeof(link)),memset(val,0,sizeof(val));}
    void build(){
        Rep(i,1,sz)link[i]=i;
    }
    void print(){
        Rep(i,1,n)
            Rep(j,1,m)
                printf("%d%c",val[to[i][j]],j==m?'\n':' ');
    }
    matrix operator * (const matrix &x)const {
        matrix res;
        Rep(i,1,sz)
            res.link[i]=x.link[link[i]];
        Rep(i,1,sz)res.val[x.link[i]]+=val[i],res.val[x.link[i]]%=p;
        Rep(i,1,sz)res.val[i]+=x.val[i],res.val[i]%=p;
        return res;
    }
}A[N],B,ans;

matrix Qpow(matrix base,int ind){
    matrix res;
    res.build();
    while(ind){
        if(ind&1)res=res*base;
        base=base*base;
        ind>>=1;
    }
    return res;
}

void output(matrix A){
    Rep(i,1,n){
        int last=-1e9,tim=0;
        Rep(j,1,m){
            int pos=to[i][j];
            if(A.val[pos]==last)tim++;
            else{
                if(tim)printf("%d %d ",tim,last);
                last=A.val[pos];
                tim=1;
            }
        }
        if(tim)printf("%d %d\n",tim,last);
    }
}

int main()
{
    read(n),read(m),read(x),read(p),read(t);
    Rep(i,1,n)
        Rep(j,1,m){
            int len;
            read(len);
            cin>>s;
            Rep(k,1,63/len)l[i][j]+=s;
        }
    Rep(i,1,n)
        Rep(j,1,m)
            to[i][j]=++tot;
    sz=n*m;
    Rep(k,0,62){
        Rep(i,1,n)
            Rep(j,1,m)
                switch(l[i][j][k]){
                    case 'C':
                        A[k+1].link[to[i][j]]=to[i][j];
                        A[k+1].val[to[i][j]]+=x;
                        break;
                    case 'U':
                        if(i>1)A[k+1].link[to[i][j]]=to[i-1][j];
                        break;
                    case 'D':
                        if(i<n)A[k+1].link[to[i][j]]=to[i+1][j];
                        break;
                    case 'L':
                        if(j>1)A[k+1].link[to[i][j]]=to[i][j-1];
                        break;
                    case 'R':
                        if(j<m)A[k+1].link[to[i][j]]=to[i][j+1];
                        break;
                }
    }
    if(t<=63){
        Rep(i,1,t)ans=ans*A[i];
        output(ans);
        return 0;
    }
    B.build();
    Rep(i,1,63)B=B*A[i];
    ans=Qpow(B,t/63);
    Rep(i,1,t%63)ans=ans*A[i];
    output(ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章