• bzoj2004公交线路


    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2004

    好美妙的矩阵乘。

    思考:

    0.在一个序列上。所以考虑dp。

    1.p<=10,k<=8,所以考虑状压,1表示这一站正有公交车。

    2.n<=1e9,考虑矩阵乘优化dp。

    3.因为每一步<=p,所以维护长度为p的区间中的当前状态就行了,其他位置肯定全是0。这样也压得下。

    实现:

    为了不重不漏,需要指定一个顺序一样的东西。

      比如我们可以指定最左边一定得有一辆车,而且每次状态改变一定是这辆车走了。

        转移条件就是(当前状态)<<1 与 (目标状态) 只有一位不同,即( (当前状态)<<1 & (目标状态) )==k-1。

      对称地,我们也可以指定最右边一定得有一辆车,状态改变时是随便位置的一辆车走到了这个位置。

        转移条件略。

      因为只能从左往右走,所以这两种方式比指定中间某个位置一定得有一辆车更优。

    更妙的是因为每次移动区间之前都有一个 不与之前重复的 指定位置一定有车,而本次更新出来的状态都是建立在该位置有车的前提上的,所以就能保证每一站都被停过!

    每一站都只停一次就是通过区间内有k个1来保证。

    最后需要乘一下最初的状态,就是开头有k个1的那个。

      如果我们把开始的右端看作第k个位置,结束就是在第n个位置;而且这样开始和结束的状态就都是000001111111的样子。

      如果从1~(1<<p-1)枚举数字是否合法,则第一个得到的合法状态就是000001111111的样子。

      所以最后乘一个只有[1][1]是1的状态矩阵(初始),再输出[1][1]位置的值(最终)就行啦!因为乘状态矩阵对[1][1]的值无影响,所以不乘也行。

    代码:

      合法状态不用算末位是0但有k个1的,因为没人转移给它们值,所以它们就没用了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N=155,mod=30031;
    int n,m,p,cnt,lm,list[N];
    struct Matrix{
        int v[N][N];
        void init()
        {
            for(int i=1;i<=cnt;i++)v[i][i]=1;
        }
        Matrix operator *(const Matrix &b)const
        {
            Matrix tp;memset(tp.v,0,sizeof tp.v);
            for(int i=1;i<=cnt;i++)
                for(int j=1;j<=cnt;j++)
                    for(int k=1;k<=cnt;k++)
                        (tp.v[i][j]+=v[i][k]*b.v[k][j])%=mod;
            return tp;
        }
    }res,tp;
    int num(int x)//很好 
    {
        int ct=0;
        while(x){x-=(x&-x);ct++;}
        return ct;
    }
    int main()
    {
        scanf("%d%d%d",&n,&m,&p);
        lm=(1<<p);
        for(int i=1;i<lm;i++)
            if((i&1)&&num(i)==m)list[++cnt]=i;
        for(int i=1;i<=cnt;i++)
                for(int j=1;j<=cnt;j++)
                    if(num(list[i]&(list[j]<<1))==m-1)tp.v[i][j]=1;
        int ct=n-m;res.init();
        while(ct)
        {
            if(ct&1)res=res*tp;
            tp=tp*tp;ct>>=1;
        }
        printf("%d",res.v[1][1]);
        return 0;
    }
  • 相关阅读:
    c++ 反汇编 除法优化
    python3 循环位移动
    Reverse 高校网络信息安全运维挑战赛
    2019_西湖论剑_预选赛 testre
    《C++反汇编与逆向分析技术揭秘》--算术运算和赋值
    《C++反汇编与逆向分析技术揭秘》--认识启动函数,找到用户入口
    《C++反汇编与逆向分析技术揭秘》--数据类型
    D8016 “/ZI”和“/Gy-”命令行选项不兼容
    逆向学习书籍分享
    获得PyInstaller打包exe的py源码
  • 原文地址:https://www.cnblogs.com/Narh/p/9043807.html
Copyright © 2020-2023  润新知