题目
题目链接
TUOJ
https://sim.csp.thusaac.com/contest/37/problem/2参考:第37次CCF CSP第三题 模板展开 题解_模板展开csp-CSDN博客
思路
一、核心设计思想
系统将变量分为两种存储方式:
-
直接赋值:立即计算表达式结果并存储
-
间接赋值:存储表达式结构和依赖关系,查询时动态计算
二、变量存储结构
每个变量包含两个部分:
-
固定值部分:所有直接字符串的长度总和
-
依赖列表:引用的其他变量ID
这种设计允许表达式既包含字符串字面量,也包含对其他变量的引用。
三、三种操作详解
1. 操作1:直接赋值
处理流程:
-
立即计算所有部分的总和
-
字符串字面量直接累加长度
-
变量引用(
$开头)递归计算其当前值并累加 -
将最终结果存入变量的固定值部分,清空依赖列表
特点:赋值时完成所有计算,后续查询直接返回值
2. 操作2:间接赋值
处理流程:
-
分离字符串和变量引用
-
字符串字面量累加到固定值部分
-
变量引用记录到依赖列表中
-
不进行实际计算
特点:建立依赖关系网,查询时才计算
3. 操作3:查询变量值
处理流程:
-
检查缓存(
len数组) -
若未缓存:固定值 + 递归计算所有依赖变量的值
-
缓存结果后返回
四、计算与缓存机制
递归计算:
-
对于间接赋值的变量,需要递归计算其依赖的所有变量
-
自动处理多层嵌套的变量引用
缓存优化:
-
len数组缓存每个变量的计算结果 -
每次操作开始时清空缓存(简单但低效)
-
避免重复计算相同变量
代码
【对上面的代码按照自己的习惯进行了改写,但是逻辑基本一致】
cpp
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define debug(a) cout<<"debug:"<<a<<endl;
const int N=2e3+5;
const int MOD=1e9+7;
int cnt=0;
struct var{
// int kind; //1:直接 2:间接 没用
ll l; //可能会爆int
vector<int>r; //依赖
};
vector<var>v(N);
int len[N];
unordered_map<string,int>mp;
int get_idx(string s)
{
// if(mp[s]!=NULL) ; //warn:不能mp[s]!=NULl来判断;写出mp[s]就会自动创建并赋值为0
if(mp.count(s)==0) mp[s]=cnt++; //这么判断才对
return mp[s];
}
int get_value(int idx) //传入下标
{
if(len[idx]!=-1) return len[idx];
ll ans=v[idx].l;//int可能会爆
for(auto k:v[idx].r)
{
//warn不能只加基础值,可能该变量间接引用的其他变量也是间接赋值,所以要递归计算
//ans=(ans+v[k].l)%MOD;
ans=(ans+get_value(k))%MOD;
}
return ans;
}
void solve()
{
int n; cin>>n;
cin.get();
while(n--)
{
memset(len,-1,sizeof(len)); //warn:应该是-1代表未计算
string line,s1;
getline(cin,line);
stringstream ss(line);
int op;
ss>>op>>s1;
int idx=get_idx(s1);
if(op==1) //直接赋值
{
v[idx].r.clear();
// v[idx].l=0; //WARN:可以把自己直接赋值给自己
string now;
ll res=0; //WARN:局部变量初始化
while (ss>>now)
{
if(now[0]=='$')
{
now.erase(0,1); //删$
res=(res+get_value(get_idx(now)))%MOD;
}
else res=(res+now.size())%MOD; //WARN:不带$的是字面量不是变量
}
v[idx].l=res;
}
else if(op==2) //间接赋值
{
v[idx].r.clear();
v[idx].l=0; //不会自己依赖自己,否则成环
ll res=0;
string now;
while (ss>>now)
{
if(now[0]=='$')
{
now.erase(0,1); //删$
v[idx].r.push_back(get_idx(now));
}
else res=(res+now.size())%MOD;
}
v[idx].l=res;
}
else if(op==3) cout<<get_value(idx)<<endl;
}
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0);
solve();
return 0;
}