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

浙公网安备 33010602011771号