1 条题解

  • 0
    @ 2025-8-24 21:51:24

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar zhzh2001
    **

    搬运于2025-08-24 21:51:24,当前版本为作者最后更新于2017-05-09 20:06:17,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题解

    初看这道题感觉十分难做,除了麻烦的语法分析,还需要优化循环。

    官方题解

    循环不嵌套

    此时直接模拟即可,最多只有50个循环。

    只有一个变量

    当只有一个变量的时候,可以得到一个通项公式,但实际并不实用。具体可参考官方题解。

    使用矩阵乘法

    理论上,通过公式也可以做这道题,但是用矩阵乘法更加简洁。

    构造转移矩阵

    矩阵中包含各个变量的转移关系。对于矩阵A和B,先后执行等价于乘以A*B。而A循环n次则等价于乘以AnA^n

    对于nsq = ( nsq ) + ( ( n ) + ( ( n ) + ( 1 ) ) ),构造矩阵为

        1    n    nsq
    1    1
    n        1
    nsq    1    2    1
    

    注意转移没有被赋值的量。

    另外,直接忽略表达式中的括号,因为加法没有优先级问题。

    处理嵌套循环

    维护一个栈,保存每层循环的结果和循环次数。

    有新循环时,压入一个单位矩阵;循环退出时,弹出栈顶,执行快速幂,并与下一层相乘。

    时间复杂度

    矩阵大小不超过100x100,最多有50个循环,每个循环最多计算log2(105)17log_2(10^5) \sim 17次矩阵乘法。实际上运算量不到1亿,可以轻松通过。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=105,MOD=1e9+7;
    int n,cnt[N];
    //cnt[]保存每层循环的次数
    struct matrix
    {
        long long mat[N][N];
        matrix()
        {
            memset(mat,0,sizeof(mat));
        }
        matrix operator*(const matrix& rhs)const
        {
            matrix ans;
            for(int i=1;i<=n;i++)
                for(int k=1;k<=n;k++)
                    for(int j=1;j<=n;j++)
                    {
                        ans.mat[i][j]=(ans.mat[i][j]+mat[i][k]*rhs.mat[k][j])%MOD;
                        assert(ans.mat[i][j]>=0);
                    }
            return ans;
        }
        matrix operator*=(const matrix& rhs)
        {
            return *this=*this*rhs;
        }
    }S[N];
    //矩阵栈
    matrix I()
    {
        matrix ans;
        for(int i=1;i<=n;i++)
            ans.mat[i][i]=1;
        return ans;
    }
    //单位矩阵
    matrix qpow(matrix a,int b)
    {
        matrix ans=I();
        do
        {
            if(b&1)
                ans*=a;
            a*=a;
        }
        while(b/=2);
        return ans;
    }
    //矩阵快速幂
    string code[N];
    template<typename T>
    inline T get_token(const string& s)
    {
        stringstream ss(s);
        T ret;
        ss>>ret;
        return ret;
    }
    //将字符串s中的下一个内容转换为T
    int main()
    {
        map<string,int> var;
          //保存变量名对应的编号
        var["1"]=1;
        //没什么用
        int lines=0;
        n=1;
        while(getline(cin,code[++lines]))
            if(code[lines].find('=')!=string::npos)
            {
                string name=get_token<string>(code[lines]);
                  //题目保证所有变量都会为左值
                if(var.find(name)==var.end())
                    var[name]=++n;
            }
        lines--;
        int sp=1;
        S[sp]=I();
        for(int i=1;i<=lines;i++)
            if(code[i].substr(0,6)=="RETURN")
                cout<<S[sp].mat[var[get_token<string>(code[i].substr(6))]][1]<<endl;
                //运算结果保存在矩阵第一列中
            else
                if(code[i].find("MOO")!=string::npos)
                  //新循环
                {
                    S[++sp]=I();
                    cnt[sp]=get_token<int>(code[i]);
                }
                else
                    if(code[i].find('}')!=string::npos)
                      //循环结束
                    {
                        S[sp-1]=qpow(S[sp],cnt[sp])*S[sp-1];
                        sp--;
                    }
                    else
                    {
                        matrix now;
                        int row=var[get_token<string>(code[i])],p=code[i].find('=')+1;
                        stringstream ss(code[i].substr(p));
                        string token;
                        while(ss>>token)
                        {
                            if(isdigit(token[0]))
                                now.mat[row][1]+=get_token<int>(token);
                                  //累加常数
                            else
                                if(isalpha(token[0]))
                                    now.mat[row][var[token]]++;
                                      //累加变量
                        }
                        for(int i=1;i<=n;i++)
                            if(i!=row)
                                now.mat[i][i]=1;
                      //转移未赋值的量
                        S[sp]=now*S[sp];
                    }
        return 0;
    }
    

    语法分析时应该充分利用空格,同时也要防止多余的空格。

    • 1

    信息

    ID
    1129
    时间
    1000ms
    内存
    125MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者