【洛谷P3666】【USACO17OPEN】COWBASIC (字符串解析+矩阵乘法)

本文介绍了解决洛谷P3666问题的一种高效方法,利用矩阵乘法优化原始模拟算法。面对庞大的计算量,文章提出通过建立树形结构并运用矩阵乘法来减少计算次数,最终实现对问题的有效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       链接:洛谷P3666

       一看到这道题,很容易想到模拟,但是循环最多有 49 49 层,每层都可能要循环 105 10 5 次,总的就要 10245 10 245 次,显然是通过不了的。

       换个思路,我们也可能可以得到通项公式,但是计算难度有些大,像我这样的蒟蒻是永远也推不出来的。

       这时我们来考虑矩阵乘法,思路一下就明朗了,我们把字符串解析一遍,建出一棵树,剩下来的全可以靠矩乘搞定啦!

       于是这题就变成了一道码农题。。。

       不说了,再来算一下复杂度,最坏情况要做 993×98 99 3 × 98 次,还是可以通过的,但在洛谷上得开 O2 O 2 。。。

       蒟蒻的跑得奇慢无比的代码:

#pragma GCC optimize("O3")
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
const int md=1e9+7;
string buf;
string str[400];
int n;
map<string,int>mp;
struct mat{
    int a[110][110];
    int h,w;
    mat(){memset(a,0,sizeof(a));h=w=0;} 
    mat operator*(mat u)const
    {
        mat res;
        res.h=h;res.w=u.w;
        for(int i=1;i<=h;i++)
        {
            for(int j=1;j<=u.w;j++)
            {
                for(int k=1;k<=w;k++)
                {
                    res.a[i][j]+=1LL*a[i][k]*u.a[k][j]%md;
                    if(res.a[i][j]>=md)res.a[i][j]-=md;
                }
            }
        }
        return res;
    }
    void operator*=(mat u)
    {
        *this=*this*u;
    }
};
void skip(string s,int &p)
{
    while(p<s.size() && s[p]==' ')p++;
}
void rskip(string s,int &p)
{
    while(p>=0 && s[p]==' ')p--;
}
string getstr(string s,int &p)
{
    skip(s,p);
    string res="";
    while(p<s.size() && s[p]!=' ')res+=s[p++];
    skip(s,p);
    return res;
}
int getval(string s)
{
    int res=0;
    for(int i=0;i<s.size();i++)
    {
        if(!isdigit(s[i]))return -1;
        res=res*10+s[i]-'0';
    }
    return res;
}
mat matrix[400];
int times[400];
vector<int>G[400];
int tot,cnt;
mat qmul(mat x,int p)
{
    mat res;
    res.h=x.h;
    res.w=x.w;
    for(int i=1;i<=res.h;i++)res.a[i][i]=1;
    for(;p;p>>=1,x*=x)if(p&1)res*=x;
    return res;
}
int dfs(int x,int p)
{
    if(x>=n)return x;
    int pos=(int)str[x].size()-1;
    rskip(str[x],pos);
    if(str[x][pos]=='}')return x;
    tot++;
    G[p].push_back(tot);
    if(str[x][pos]=='{')
    {
        pos=0;
        times[tot]=getval(getstr(str[x],pos));
        x=dfs(x+1,tot);
    }
    else
    {
        int i=0;
        int var=mp[getstr(str[x],i)];
        matrix[tot].h=matrix[tot].w=cnt+1;
        for(int i=1;i<var;i++)matrix[tot].a[i][i]=1;
        for(int i=var+1;i<=cnt+1;i++)matrix[tot].a[i][i]=1;
        for(;i<str[x].size();)
        {
            string tmp=getstr(str[x],i);
            int val=getval(tmp);
            if(val==-1)
            {
                if(tmp!="(" && tmp!=")" && tmp!="+" && tmp!="=")
                {
                    matrix[tot].a[mp[tmp]][var]++;
                }
            }
            else matrix[tot].a[cnt+1][var]+=val;
        }
    }
    dfs(x+1,p);
}
mat solve(int x)
{
    if(!G[x].size())return matrix[x];
    matrix[x]=solve(G[x][0]);
    for(int i=1;i<G[x].size();i++)matrix[x]*=solve(G[x][i]);
    return matrix[x]=qmul(matrix[x],times[x]);
}
int main()
{
    while(getline(cin,buf))
    {
        str[++n]=buf;
        int pos=(int)buf.size()-1;
        rskip(buf,pos);
        if(buf[pos]=='{' || buf[pos]=='}')continue;
        for(int i=0;i<buf.size();)
        {
            string tmp=getstr(buf,i);
            if(getval(tmp)==-1)
            {
                if(tmp!="(" && tmp!=")" && tmp!="+" && tmp!="=" && tmp!="RETURN" && !mp[tmp])
                {
                    mp[tmp]=++cnt;
                }
            }
        }
    }
    times[0]=1;
    dfs(1,0);
    solve(0);
    mat res;
    res.h=1;
    res.w=cnt+1;
    res.a[1][cnt+1]=1;
    mat tmp=solve(0);
    res*=tmp;
    int pos=0;
    getstr(str[n],pos);
    printf("%d",res.a[1][mp[getstr(str[n],pos)]]);
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值