[USACO17OPEN] COWBASIC

本文深入探讨了使用手写栈和矩阵乘法技巧解决循环语句解析问题的方法,强调了清空手写栈的重要性,避免了冗长的调试过程。通过将语法分为四种类型,利用STL进行高效处理,最终实现了循环语句的正确解析。

手写栈一定要清空!!!

手写栈一定要清空!!!

手写栈一定要清空!!!

重要的事情说三遍

因为这个地方debug了2天…

首先,我们应该把这些东西都读进来,因为在线读在线做的话不太好做

我第一天试着边读边做,应该也能弄,就是判断一下小括号和大括号数看看有没有换行就可以,但是细节挺多,交上去成功拿到了6分(样例分)

于是第二天我选择把所有东西都读进来做(洛谷运势:宜重构代码),然后猛然发现第一天脑子抽到没有想到string.find(),STL大法好

然后瞎搞(这种题能怎么说做法呢…),注意不能一次一次的加,需要矩阵乘法加速一下,因为有常数项的因素,所以我们的矩阵大小应该是变量数+1,还有一个1的位置

显然我们需要用栈来模拟循环

我们可以在外面套上一个虚拟的循环,这样就解决了那些奇奇怪怪的问题

我们把语法分成四种类型

1.开始循环语句

判断方法:string.find(’{’)

做法:向栈顶压入一个单位矩阵记录下一个循环的答案

2.结束循环语句

判断方法:string.find(’}’)

做法:这个循环的上一个(栈顶-1)乘上这个循环的矩阵的循环次数次幂

3.return语句

判断方法:string.find(“RETURN”)

做法:输出

4.赋值语句

判断方法:else+else+else

做法:

因为一个赋值语句只占一行,所以我们先求出这个赋值语句的赋值变量是什么(第一个单词),然后每次去找,括号什么的直接略过,处理出这样一个矩阵,但是这个矩阵只维护了一个变量的信息,所以我们需要把这个矩阵其它的ai,ia_{i,i}ai,i都变成1,然后乘上这个矩阵所对应的答案

完成上面那些东西需要我们多写两个函数

split(string,int)split(string,int)split(string,int)

表示从string的int位置开始提取出一段连续的字符串,注意int传进去应该加一个&,因为那个变量写需要变

todigit(string)todigit(string)todigit(string)

表示把这个string转化成int类型(听说STL也能实现,然而我不会就只能自己动手写了qwq)

然后交上去,发现是0分

下载一下数据,发现有缩进!

于是我们再写一个skipskipskip表示跳过空格

然后再交上去,31分

调了2天,发现了问题,我写的是把矩阵数组整个当成一个栈了,所以这样的话我们需要每次开一个点的时候把这个点的矩阵清空一下,然后构造单位矩阵

代码:没删调试之前160行…

# include <bits/stdc++.h>
using namespace std;

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)
# define debug puts("QAQ");

typedef long long ll;
const int N=105;
const int mod=1e9+7;
const double eps=1e-7;

# define int long long

template <typename T> void read(T &x){
	x=0;int f=1;
	char c=getchar();
	for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
	for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
	x*=f;
}

map<string,int> var;
int n,num,sum;
string s[N];
int inds[N];

struct matrix{
	int a[N][N];
	matrix(){memset(a,0,sizeof(a));}
	void build(){
        memset(a,0,sizeof(a));
		Rep(i,1,num)a[i][i]=1;	
	}
	void print(){
		Rep(i,1,num)
			Rep(j,1,num)
				printf("%d%c",a[i][j],j==num?'\n':' ');	
	}
	matrix operator * (const matrix &m)const{
		matrix res;
		Rep(i,1,num)
			Rep(j,1,num)
				Rep(k,1,num)
					res.a[i][j]=1ll*(res.a[i][j]+1ll*a[i][k]*m.a[k][j])%mod;
		return res;	
	}
}mat[N];

matrix Qpow(matrix base,int ind){
	matrix res;
	res.build();
	while(ind){
		if(ind&1)res=res*base;
		base=base*base;
		ind>>=1;
	}
	return res;
}

void skip(string s,int &p){
    while(p<s.size()&&!((s[p]>='0'&&s[p]<='9')||(s[p]>='a'&&s[p]<='z')||s[p]=='{'||s[p]=='}'||s[p]=='('||s[p]==')'))p++;
}

string split(string s,int &p){
	string res;
    skip(s,p);
	while(p<s.size()&&((s[p]>='0'&&s[p]<='9')||(s[p]>='a'&&s[p]<='z')||s[p]=='{'||s[p]=='}'||s[p]=='('||s[p]==')'))res+=s[p++];
	return res;	
}

int todigit(string s){
	int num=0;
	for(int i=0;i<s.size();i++)
		num=num*10+s[i]-'0';
	return num;	
}

signed main()
{
    num=1;
	while(getline(cin,s[++n]))
		if(s[n].find('=')!=string::npos){
			int zero=0;
			string vars=split(s[n],zero);
			if(!var[vars])
				var[vars]=++num;	
		}
	sum=1;
	mat[sum].build();
	Rep(i,1,n){
		int zero=0;
		if(s[i].find("RETURN")!=string::npos){
			int seven=7;
			printf("%lld\n",mat[sum].a[var[split(s[i],seven)]][1]);
			return 0;
		}
		else
			if(s[i].find('{')!=string::npos){
				mat[++sum].build();
                zero=0;
				inds[sum]=todigit(split(s[i],zero));
			}
			else
				if(s[i].find('}')!=string::npos){
					mat[sum-1]=Qpow(mat[sum],inds[sum])*mat[sum-1];
					sum--;
				}
				else{
					matrix A;
					int p=0;
					string t=split(s[i],p);
                    p=s[i].find('=')+1;
					int vars=var[t];
					for(;p<s[i].size();p++){
                        skip(s[i],p);
						if(isdigit(s[i][p])){
							A.a[vars][1]+=todigit(split(s[i],p));
                            A.a[vars][1]%=mod;
                        }
						else
							if(isalpha(s[i][p]))
								A.a[vars][var[split(s[i],p)]]++;
                    Rep(i,1,num)if(i!=vars)A.a[i][i]=1;
					mat[sum]=A*mat[sum];
				}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值