• [SDOI2019] 染色


    题意:

    给定$2 imes n$的格点图。其中一些结点有着已知的颜色,其余的结点还没有被染色。一个合法的染色方案不允许相邻结点有相同的染色。

    现在一共有c种不同的颜色,依次记为1到n。请问有多少对未染色结点的合法染色方案?

    $100pts:n,cleq 10^{5}$;

    $96pts:n,cleq 10^{4}$。

    题解:

    首先想到一个$O(nc^{2})$的dp,但一分都没有。

    而且后面的方案和已经决定的方案有关,于是这题除了dp没有其他做法。

    于是考虑优化dp。注意到如果将原图中所有的空白列删掉,我们就可以$O(nc)$做了。

    那么我们可以考虑预处理出$g(i,j,k)$表示两个非空白列i,j中间的k个空白列对答案的贡献。

    不过其实不需要记录$(i,j)$,我们可以按照这四个颜色互相是否相同分出5种等价类,大概是

    1. $left[ egin{matrix} x & cdots & x\ y & cdots & y end{matrix} ight]$
    2. $left[ egin{matrix} x & cdots & y\ y & cdots & x end{matrix} ight]$
    3. $left[ egin{matrix} x & cdots & z\ y & cdots & y end{matrix} ight]$或$left[ egin{matrix} x & cdots & x\ y & cdots & z end{matrix} ight]$
    4. $left[ egin{matrix} x & cdots & z\ y & cdots & x end{matrix} ight]$或$left[ egin{matrix} x & cdots & y\ y & cdots & z end{matrix} ight]$
    5. $left[ egin{matrix} x & cdots & z\ y & cdots & w end{matrix} ight]$

    显然每个等价类里的$(i,j,k)$算出来是相等的,那么只需要维护$g(5,k)$了,推一下转移式子即可。

    注意推出来的式子里z,w是不固定的,而原dp转移时这四个数都是固定的,所以还要除一下。

    然后回到原dp,对于两个非空白列我们再分类讨论一下有没有无空白列,枚举当前这一列填的数转移即可(之前那列填的数直接整体转移)。

    这样可以获得96分的好成绩,然后发现这个dp的转移跟这场比赛的第一题是一样的(伏笔消除),于是复制粘贴再改改就可以100了。

    虽然这么说……100也只有石神这种代码能力很强的强者能写出来,我是真的不行了(

    套路:

    • 子问题之间互相影响$ ightarrow$一般只有dp做法。
    • 有大量具有相同性质的元素$ ightarrow$合并计算以降低复杂度。

    代码:

    #include<bits/stdc++.h>
    #define maxn 10005
    #define maxm 500005
    #define inf 0x7fffffff
    #define mod 1000000009
    #define ll long long
    #define rint register int
    #define debug(x) cerr<<#x<<": "<<x<<endl
    #define fgx cerr<<"--------------"<<endl
    #define dgx cerr<<"=============="<<endl
    
    using namespace std;
    ll g[maxn][5],A[maxn][2],dp[maxn],tp[maxn],pw[maxn];
    
    inline ll read(){
        ll x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    
    inline bool isw(ll x){return (A[x][0]!=0)&&(A[x][1]!=0);}
    inline bool isz(ll x){return (A[x][0]==0)&&(A[x][1]==0);}
    
    inline ll power(ll a,ll b){
        ll ans=1;
        while(b){
            if(b&1) ans=ans*a%mod;
            a=a*a%mod,b>>=1;
        }    
        return ans;
    }
    
    inline ll chk(ll a,ll b,ll c,ll d){
        if(a==c && b==d) return 0;
        else if(a==d && b==c) return 1;
        else if(a==c || b==d) return 2;
        else if(a==d || b==c) return 3;
        else return 4;
    }
    
    inline void init(ll n,ll c){
        g[0][0]=1;
        int nxt[5][5]={
        {0,1,0,c-2,(c-2)*(c-3)%mod},
        {1,0,c-2,0,(c-2)*(c-3)%mod},
        {0,2,c-2,2*c-5,2*(c-3)*(c-3)%mod},
        {2,0,2*c-5,c-2,2*(c-3)*(c-3)%mod},
        {1,1,c-3,c-3,((c-4)*(c-4)%mod+c-3)%mod}};
        for(rint i=1;i<=n;i++)
            for(rint j=0;j<5;j++)
                for(rint k=0;k<5;k++)
                    g[i][j]=(g[i][j]+g[i-1][k]*nxt[k][j]%mod)%mod;
        ll iv1=power(c-2,mod-2),iv2=power((c-2)*(c-3)%mod,mod-2);
        for(rint i=1;i<=n;i++){
            g[i][2]=g[i][2]*iv1%mod;
            g[i][3]=g[i][3]*iv1%mod;
            g[i][4]=g[i][4]*iv2%mod;
        }
    }
    
    int main(){
        ll n=read(),c=read(),sum=0; init(n,c);
        for(rint i=1;i<=n;i++) A[i][0]=read();
        for(rint i=1;i<=n;i++) A[i][1]=read();
        pw[0]=1; for(rint i=1;i<=n;i++) pw[i]=pw[i-1]*((c-2)*(c-2)%mod+c-1)%mod;
        int p=1; while(isz(p) && p<=n) p++;
        if(isw(p)) dp[0]=tp[0]=sum=pw[p-1];
        else for(rint k=1;k<=c;k++){
            if(k==(A[p][0]?A[p][0]:A[p][1])) continue;
            dp[k]=tp[k]=pw[p-1],sum=(sum+dp[k])%mod;
        }
        for(rint i=p,j=p+1;i<=n,j<=n;i=j,j=i+1){
            while(isz(j) && j<=n) j++;
            if(j>n){for(rint k=0;k<=c;k++) dp[k]=dp[k]*pw[n-i]%mod;break;}
            if(isw(i) && isw(j)){
                memset(dp,0,sizeof(dp)),sum=0;
                int type=chk(A[i][0],A[i][1],A[j][0],A[j][1]);
                dp[0]=tp[0]*g[j-i][type]%mod,sum=dp[0];
                memcpy(tp,dp,sizeof(dp));
            }
            else if(isw(i)){
                memset(dp,0,sizeof(dp)),sum=0;
                for(rint k=1;k<=c;k++){
                    if(k==(A[j][0]?A[j][0]:A[j][1])) continue;
                    int type=chk(A[i][0],A[i][1],A[j][0]?A[j][0]:k,A[j][1]?A[j][1]:k);
                    dp[k]=tp[0]*g[j-i][type]%mod,sum=(sum+dp[k])%mod;
                }
                memcpy(tp,dp,sizeof(dp));
            }
            else if(isw(j)){
                memset(dp,0,sizeof(dp)),sum=0;
                for(rint k=1;k<=c;k++){
                    int type=chk(A[i][0]?A[i][0]:k,A[i][1]?A[i][1]:k,A[j][0],A[j][1]);
                    dp[0]=(dp[0]+tp[k]*g[j-i][type]%mod)%mod,sum=dp[0];
                }
                memcpy(tp,dp,sizeof(dp));
            }
            else{
                memset(dp,0,sizeof(dp));
                for(rint k=1;k<=c;k++){
                    ll a=A[i][0]?A[i][0]:A[i][1],b=A[j][0]?A[j][0]:A[j][1],ts=sum;
                    if(k==b) continue;
                    if(k!=a){
                        int kk=k,type=chk(A[i][0]?A[i][0]:kk,A[i][1]?A[i][1]:kk,A[j][0]?A[j][0]:k,A[j][1]?A[j][1]:k);
                        dp[k]=(dp[k]+tp[kk]*g[j-i][type]%mod)%mod,ts=(ts-tp[kk]+mod)%mod;
                    }
                    if(b!=a){
                        int kk=b,type=chk(A[i][0]?A[i][0]:kk,A[i][1]?A[i][1]:kk,A[j][0]?A[j][0]:k,A[j][1]?A[j][1]:k);
                        dp[k]=(dp[k]+tp[kk]*g[j-i][type]%mod)%mod,ts=(ts-tp[kk]+mod)%mod;
                    }
                    int type=chk(A[i][0]?A[i][0]:inf,A[i][1]?A[i][1]:inf,A[j][0]?A[j][0]:k,A[j][1]?A[j][1]:k);
                    dp[k]=(dp[k]+ts*g[j-i][type]%mod)%mod;
                }
                sum=0; for(rint k=1;k<=c;k++) sum=(sum+dp[k])%mod;
                memcpy(tp,dp,sizeof(dp));
            }
        }
        ll ans=0;
        for(rint i=0;i<=c;i++) ans=(ans+dp[i])%mod;
        printf("%lld
    ",ans);
        return 0;
    }
    染色
  • 相关阅读:
    02方法 课后作业1
    HDU 1518
    POJ 2406
    HDU 1953
    HDU 1272
    POJ -- 3842
    POJ -- 3233 求“等比矩阵”前n(n <=10^9)项和
    POJ ---3070 (矩阵乘法求Fibonacci 数列)
    POJ --- 3613 (K步最短路+矩阵快速幂+floyd)
    POJ --- 2918 求解数独
  • 原文地址:https://www.cnblogs.com/YSFAC/p/13091252.html
Copyright © 2020-2023  润新知