CCF-CSP 37-3 模板展开(templating)【C++】

题目

题目链接

TUOJhttps://sim.csp.thusaac.com/contest/37/problem/2参考:第37次CCF CSP第三题 模板展开 题解_模板展开csp-CSDN博客

思路

一、核心设计思想

系统将变量分为两种存储方式:

  1. 直接赋值:立即计算表达式结果并存储

  2. 间接赋值:存储表达式结构和依赖关系,查询时动态计算

二、变量存储结构

每个变量包含两个部分:

  • 固定值部分:所有直接字符串的长度总和

  • 依赖列表:引用的其他变量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;	
} 
相关推荐
We་ct11 小时前
LeetCode 42. 接雨水:双指针解法深度剖析与全方法汇总
前端·算法·leetcode·typescript
液态不合群11 小时前
如何提升 C# 应用中的性能
开发语言·算法·c#
诗远Yolanda11 小时前
EI国际会议-通信技术、电子学与信号处理(CTESP 2026)
图像处理·人工智能·算法·计算机视觉·机器人·信息与通信·信号处理
程序员-King.11 小时前
day165—递归—最长回文子序列(LeetCode-516)
算法·leetcode·深度优先·递归
BHXDML11 小时前
推导神经网络前向后向传播算法的优化迭代公式
神经网络·算法·机器学习
2401_8414956411 小时前
【LeetCode刷题】删除链表的倒数第N个结点
数据结构·python·算法·leetcode·链表·遍历·双指针
叫我:松哥11 小时前
基于YOLO深度学习算法的人群密集监测与统计分析预警系统,实现人群密集度的实时监测、智能分析和预警功能,支持图片和视频流两种输入方式
人工智能·深度学习·算法·yolo·机器学习·数据分析·flask
你撅嘴真丑11 小时前
STL练习
开发语言·c++·算法
bybitq11 小时前
cmake构建c++项目时,vscode/cursor无法识别头文件路径,导致报错,解决方案
开发语言·c++·vscode
苦藤新鸡11 小时前
28.两数相加,进位制
数据结构·算法·链表·力扣