8.28

在高中自习,但今天不是很想刷题

去看了CSP-S2023,发现CSP真的很喜欢动态规划

于是打算做一下动态规划的专题

P3146

题目

很明显的区间动规

设计状态 \(dp[l][r]\) 表示从 \(l\)\(r\) 合成成一个数的值

\[dp[l][r]=Max_{i=l}^{r-1} \,(dp[l][i]+1) \times [dp[l][i]==dp[i+1][r]] \]

前提是 \(dp[l][i]\) 是可以合成成一个数的,不然可能会凭空出现一个 \(1\)

若没有特判该情况,则你会 \(Wa\) 掉最后一个点

CODE
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
const int maxn=305;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
	x=(f ? -x : x);
	return;
}
int dp[maxn][maxn];
int n;
int a[maxn];
int main(){
	read(n);
	int ans=0;
	for(int i=1;i<=n;i++) read(a[i]),dp[i][i]=a[i],ans=max(ans,a[i]);
	for(int s=2;s<=n;s++){
		for(int l=1,r=s;r<=n;l++,r++){
			for(int i=l;i<r;i++){
				if(dp[l][i]&&dp[l][i]==dp[i+1][r]){
					dp[l][r]=max(dp[l][r],dp[l][i]+1);
				}
			}
			ans=max(ans,dp[l][r]);
		}
	}
	printf("%d",ans);
	return 0;
}
//^o^

P3147

题目

前一题的升级版

我们会发现其值域范围很小

那么那能不能把值作为一维来设计状态呢?

设计状态 \(dp[i][j]\) 表示从 \(j\) 开始合成,合到值为 \(i\) 时的末尾位置

若取 \(262144\)\(40\) ,合成后会得到 \(58\),所以合成出来的值域不会超过 \(58\)

\[dp[i][j]=dp[i-1][dp[i-1][j]] \]

CODE
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
const int maxn=262144,maxm=61;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
	x=(f ? -x : x);
	return;
}
int dp[maxm][maxn];
int a[maxn];
int n;
int main(){
	read(n);
	for(int i=1;i<=n;i++){
		read(a[i]);
		dp[a[i]][i]=i+1;
	}
	int ans=0;
	for(int i=1;i<=maxm;i++){
		for(int j=1;j<=n;j++){
			if(!dp[i][j]) dp[i][j]=dp[i-1][dp[i-1][j]];
			if(dp[i][j]) ans=i;
		}
	}
	printf("%d",ans);
	return 0;
}
//^o^

P9753

题目

设计状态 \(f[i]\) 表示以第 \(i\) 位结尾的合法子串个数,\(g[i]\) 为最大的满足 \([g[i],i]\) 是可消除区间的位置

那么转移显然

\[f[i]=f[g[i]-1]+1 \]

所以我们只需要维护 \(g\) 数组就可以了

这有点类似 \(KMP\) ,从 \(i-1\) 开始,一只找合法的区间并向后跳,直到跳到 \(s[j]=s[i]\) 为止

CODE
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
const int maxn=2e6+5;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
	x=(f ? -x : x);
}
int n;
char s[maxn];
int g[maxn];
int f[maxn];
int main(){
	read(n),scanf("%s",s+1);
	LL ans=0;
	for(int i=1;i<=n;i++){
		for(int j=i-1;j>0;j=g[j]-1){
			if(s[j]==s[i]){
				g[i]=j;
				break;
			}
		}
		if(g[i]) f[i]=f[g[i]-1]+1;
		ans+=f[i];
	}
	printf("%lld",ans);
	return 0;
}
//^o^

P9754

题目

调了一个晚自习,还是没有出来

又只能放代码尸体了

CODE
#include<bits/stdc++.h>
#define fst first
#define sec second
#define mkp(a,b) make_pair(a,b)
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
typedef pair<LL,int> pii;
const int maxn=155;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
	x=(f ? -x : x);
}
void read(LL& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
	x=(f ? -x : x);
}
struct edge{
	string name;
	int to;
};
pii d[maxn];
vector<edge> mp[maxn];
unordered_map<string,int> m;
unordered_map<string,pii> var;
set<pii> va;
int n;
int tot=0;
LL len=0;
int main(){
	freopen("P9754_6.in","r",stdin);
	read(n);
	int op,p;
	string s,a,b;
	LL ar;
	m["byte"]=++tot,d[tot]=mkp(1,1);
	m["short"]=++tot,d[tot]=mkp(2,2);
	m["int"]=++tot,d[tot]=mkp(4,4);
	m["long"]=++tot,d[tot]=mkp(8,8);//空间大小+对齐要求
	while(n--){
		read(op);
		if(op==1){
			cin>>s;
			m[s]=++tot;
			read(p);
			LL lst=0;
			while(p--){
				cin>>a>>b;
				mp[tot].push_back((edge){b,m[a]});
				d[tot].sec=max(d[tot].sec,d[m[a]].sec);
				lst=ceil(1.0*lst/d[m[a]].sec)*d[m[a]].sec+d[m[a]].fst;
			}
			d[tot].fst=lst;
			//cout<<"ans=";
			printf("%lld %d\n",d[tot].fst,d[tot].sec);
		}
		if(op==2){
			cin>>a>>b;
			var[b]=mkp(ceil(1.0*len/d[m[a]].sec)*d[m[a]].sec,m[a]);
			va.insert(var[b]);
			len=var[b].fst+d[m[a]].fst;
			//cout<<"ans=";
			printf("%lld\n",var[b].fst);
		}
		if(op==3){
			cin>>s;
			//cout<<"ans=";
			s.append(1,'.');
			int k=0;
			a.clear();
			while(s[k]!='.') a.append(1,s[k++]);
			int now=var[a].sec;
			LL ans=var[a].fst;
			a.clear();
			for(int i=k+1;i<(int)s.size();i++){
				if(s[i]=='.'){
					for(int j=0;j<(int)mp[now].size();j++){
						int v=mp[now][j].to;
						if(mp[now][j].name==a){
							ans=ceil(1.0*ans/d[v].sec)*d[v].sec;
							now=v;
							break;
						}
						else{
							ans=ceil(1.0*ans/d[v].sec)*d[v].sec+d[v].fst;
						}
					}
					a.clear();
				}
				else{
					a.append(1,s[i]);
				}
			}
			printf("%lld\n",ans);
		}
		if(op==4){
			read(ar);
			//cout<<"ans=";
			vector<string> v;
			LL l=0;
			int now=0;
			for(auto i=va.begin();i!=va.end();i++){
				if(i->fst<=ar) l=i->fst,now=i->sec;
				else break;
			}
			for(auto i=var.begin();i!=var.end();i++){
				if(i->sec.fst==l){
					v.push_back(i->fst);
					break;
				}
			}
			if(!now){
				cout<<"ERR\n";
				continue;
			}
			while(now>4){
				int tp=0;
				for(int j=0;j<(int)mp[now].size();j++){
					int v=mp[now][j].to;
					LL li=ceil(1.0*l/d[v].sec)*d[v].sec+d[v].fst;
					if(li>ar){
						break;
					}
					else{
						l=li,tp=j;
					}
				}
				v.push_back(mp[now][tp].name);
				now=mp[now][tp].to;
			}
			if(ar-l>=d[now].fst){
				cout<<"ERR";
			}
			else{
				cout<<v[0];
				for(int i=1;i<(int)v.size();i++){
					cout<<'.'<<v[i];
				}
			}
			putchar('\n');
		}
	}
	return 0;
}
//^o^

赌一下今年不考大模拟,我再也不写了TT

posted @ 2025-08-28 20:59  huangems  阅读(11)  评论(0)    收藏  举报