• [bzoj4851][Jsoi2016]位运算【矩阵乘法】【状压dp】


    【题目链接】
      https://www.lydsy.com/JudgeOnline/problem.php?id=4851
    【题解】
      题目中说选的数两两都不相同,那么我们状压记是否满足了不同的限制,并且规定前一个比后一个大。再开一位记最前面的一个是否小于S。转移时,2n枚举这一位填什么。然后判断是否合法。我们的目标是求出对于每一种开始的状态,在|S|步后到每种状态的方案数。这样的复杂度是O(2N2N2N|S|N)的,不可以接受。
      观察后发现,在位数相同时,转移是固定的,所以可以预处理出所有的转移。这样复杂度变为了O(2N2NN|S|+2N2N2N|S|)可以接受。
      接下来就是套路的矩阵乘法。复杂度O((2N)3logK)
      

    /* --------------
        user Vanisher
        problem bzoj-4851 
    ----------------*/
    # include <bits/stdc++.h>
    # define    ll      long long
    # define    inf     0x3f3f3f3f
    # define    N       7
    # define    L       51
    # define    P       1000000007
    using namespace std;
    int read(){
        int tmp=0, fh=1; char ch=getchar();
        while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
        while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
        return tmp*fh;
    }
    struct Metrix{
        int num[1<<N][1<<N];
        void none(){
            memset(num,0,sizeof(num));
            for (int i=0; i<(1<<N); i++)
                num[i][i]=1;
        }
    }mp,nex;
    Metrix operator *(Metrix a, Metrix b){
        for (int i=0; i<(1<<N); i++)
            for (int j=0; j<(1<<N); j++){
                nex.num[i][j]=0;
                for (int t=0; t<(1<<N); t++)
                    nex.num[i][j]=(nex.num[i][j]+1ll*a.num[i][t]*b.num[t][j])%P;
            }
        return nex;
    }
    int f[L][1<<N],n,k,num[N+1],to[1<<N][1<<N][L];
    char s[L],l;
    int cmp(int x, int y, int las){
        if (las!=0) return 1;
        if (x>y) return -1;
        if (x==y) return 0;
        return 1;
    }
    Metrix mypow(Metrix x, int y){
        Metrix i=x; x.none();
        while (y>0){
            if (y%2==1) x=x*i;
            i=i*i;
            y/=2;
        }
        return x;
    }
    int main(){
        n=read(), k=read();
        scanf("
    %s",s+1); l=strlen(s+1);
        for (int i=1; i<=l; i++) s[i]=s[i]-'0';
        for (int i=0; i<(1<<n); i++)
            for (int j=0; j<(1<<n); j++){
                int cnt=0;
                for (int t=1; t<=n; t++) num[t]=((j&(1<<(t-1)))!=0);
                for (int t=1; t<=n; t++) cnt=cnt+num[t];
                if (cnt%2==0){
                    for (int p=1; p<=l; p++){
                        num[0]=s[p]; int now=0, flag=true;
                        for (int t=1; t<=n; t++){
                            int tmp=cmp(num[t],num[t-1],i&(1<<(t-1)));
                            if (tmp==-1){flag=false; break;}
                            now=now+tmp*(1<<(t-1));
                        }
                        if (flag) to[i][j][p]=now;
                            else to[i][j][p]=-1;
                    }
                }
                else for (int p=1; p<=l; p++)
                    to[i][j][p]=-1;
            }
        for (int i=0; i<(1<<n); i++){
            memset(f,0,sizeof(f));
            f[0][i]=1;
            for (int j=1; j<=l; j++)
                for (int t=0; t<(1<<n); t++){
                    if (f[j-1][t]==0) continue;
                    for (int p=0; p<(1<<n); p++){
                        int now=to[t][p][j];
                        if (now!=-1) f[j][now]=(f[j][now]+f[j-1][t])%P;
                    } 
                }
            for (int t=0; t<(1<<n); t++)
                mp.num[i][t]=f[l][t];
        }
        mp=mypow(mp,k);
        printf("%d
    ",mp.num[0][(1<<n)-1]); 
        return 0;
    }
    
  • 相关阅读:
    使用qemu模拟调试内核和debian根文件系统
    qemu无界面启动,并重定向输出到终端
    linux 音频编程
    解决Android中No resource found that matches android:TextAppearance.Material.Widget.Button.Inverse问题
    【BigData】Java基础_通用排序工具类的实现
    【BigData】Java基础_登录注册实现
    【费曼学习方法】世界上最好的学习方法
    【BigData】Java基础_接口
    【BigData】Java基础_Eclipse配置自动补全new
    【BigData】Java基础_HashSet
  • 原文地址:https://www.cnblogs.com/Vanisher/p/9135959.html
Copyright © 2020-2023  润新知