当前位置: 首页 > news >正文

CSP-S模拟37

T1:回文(string)

思路:

由于本题的数据范围较小,所以可能有多种 \(dp\) 状态,这里只呈现其中可能较典的两种外加一种暴搜最优解。

DP1:

我们设 \(f_{i,j,x,y}\) 表示使用 \(a\) 串的 \(i\) ~ \(j\)\(b\) 串的 \(x\) ~ \(y\) 能否拼成一个回文串。

首先考虑原始状态是什么样的。显然原始状态有三种大情况: \(a,b\) 中的单个字符,\(a,b\) 中相邻的两个相同的字符以及 \(a,b\) 串中相同的字符。这些显然都是初始能构成回文串的字符。

然后再考虑转移。显然有四种转移方式:\(a\) 串自己左右扩展, \(b\) 串自己左右扩展, \(a\) 串左端与 \(b\) 串右端匹配, \(a\) 串右端与 \(b\) 串左端匹配。

最后我们枚举每个串截取的长度,然后枚举起点,计算出终点。若 \(f_{i,j,x,y}\)\(1\) ,则 \(ans=max(ans,lena+lenb)\)

\(O(Tn^4)\) 的时间复杂度。跑得还是比较快的。

代码:

$code$
#include<iostream>
#include<cstring>
using namespace std;
int T,n,m,ans,f[55][55][55][55];
string a,b;
int main(){freopen("string.in","r",stdin);freopen("string.out","w",stdout);ios::sync_with_stdio(false);cin>>T;while(T--){ans=1;memset(f,0,sizeof(f));cin>>a>>b;a=' '+a;b=' '+b;n=a.size()-1;m=b.size()-1;for(int i=1;i<=n;i++) for(int j=1;j<=m+1;j++) f[i][i][j][j-1]=1;for(int j=1;j<=m;j++) for(int i=1;i<=n+1;i++) f[i][i-1][j][j]=1;for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(a[i]==b[j]) f[i][i][j][j]=1;for(int i=1;i<n;i++){if(a[i]==a[i+1]){for(int j=1;j<=m+1;j++){ans=2;f[i][i+1][j][j-1]=1;}}}for(int j=1;j<m;j++){if(b[j]==b[j+1]){for(int i=1;i<=n+1;i++){ans=2;f[i][i-1][j][j+1]=1;}}}for(int lena=0;lena<=n;lena++){for(int i=1;i<=n-lena+1;i++){int j=i+lena-1;for(int lenb=0;lenb<=m;lenb++){for(int x=1;x<=m-lenb+1;x++){int y=x+lenb-1;if(f[i][j][x][y]){ans=max(ans,lena+lenb);if(i>1&&j<n&&a[i-1]==a[j+1]) f[i-1][j+1][x][y]=1;if(x>1&&y<m&&b[x-1]==b[y+1]) f[i][j][x-1][y+1]=1;if(i>1&&y<m&&a[i-1]==b[y+1]) f[i-1][j][x][y+1]=1;if(x>1&&j<n&&a[j+1]==b[x-1]) f[i][j+1][x-1][y]=1;}}}}}cout<<ans<<'\n';}return 0;
}//题解方法 (较快) 

DP2:

我们设 \(f_{i,j,x,y}\) 表示使用 \(a\) 串的 \(i\) ~ \(j\)\(b\) 串的 \(x\) ~ \(y\) 能拼成回文串的最长长度。

还是先考虑初始状态,显然跟上面的是一样的,不过上述的状态一初始值为 \(1\) ,状态二、三的初始值为 \(2\) (因为存的是长度嘛)

然后转移就是正常的转移了。不过记得特判一下把单个字符放到另一个串里的情况喔~~

最后取 \(max\) 就好啦~~

时间复杂度也是 \(O(Tn^4)\) 的,不过或许是因为大力分讨,跑起来不如上面那个快。

$code$
#include<iostream>
#include<cstring>
using namespace std;
int T,m,n,ans,f[55][55][55][55];
string a,b;
int main(){
//	freopen("string.in","r",stdin);
//	freopen("string.out","w",stdout);ios::sync_with_stdio(false);cin>>T;while(T--){memset(f,0,sizeof(f));cin>>a>>b;a=' '+a;b=' '+b;n=a.size()-1;m=b.size()-1;for(int lena=0;lena<=n;lena++){for(int i=1;i<=n-lena+1;i++){int j=i+lena-1;for(int lenb=0;lenb<=m;lenb++){for(int x=1;x<=m-lenb+1;x++){int y=x+lenb-1;if(lena+lenb==1) f[i][j][x][y]=1;if(lena+lenb==2){if(!lena&&b[x]==b[y]) f[i][j][x][y]=2;else if(!lenb&&a[i]==a[j]) f[i][j][x][y]=2;else if(lena&&lenb&&a[i]==b[x]) f[i][j][x][y]=2;}if(lena+lenb!=f[i][j][x][y]) continue;if(i>1&&j<n&&a[i-1]==a[j+1]) f[i-1][j+1][x][y]=max(f[i-1][j+1][x][y],f[i][j][x][y]+2);if(x>1&&y<m&&b[x-1]==b[y+1]) f[i][j][x-1][y+1]=max(f[i][j][x-1][y+1],f[i][j][x][y]+2);if(i>1&&y<m&&a[i-1]==b[y+1]) f[i-1][j][x][y+1]=max(f[i-1][j][x][y+1],f[i][j][x][y]+2);if(x>1&&j<n&&b[x-1]==a[j+1]) f[i][j+1][x-1][y]=max(f[i][j+1][x-1][y],f[i][j][x][y]+2);if(!lena&&y<m&&a[i]==b[y+1]) f[i][i][x][y+1]=max(f[i][i][x][y+1],f[i][j][x][y]+2);if(!lena&&x>1&&a[i]==b[x-1]) f[i][i][x-1][y]=max(f[i][i][x-1][y],f[i][j][x][y]+2);if(!lenb&&j<n&&b[x]==a[j+1]) f[i][j+1][x][x]=max(f[i][j+1][x][x],f[i][j][x][y]+2);if(!lenb&&i>1&&b[x]==a[i-1]) f[i-1][j][x][x]=max(f[i-1][j][x][x],f[i][j][x][y]+2);}}}}int ans=0;for(int i=1;i<=n;i++){for(int j=i-1;j<=n;j++){for(int x=1;x<=m;x++){for(int y=x-1;y<=m;y++){ans=max(ans,f[i][j][x][y]);}}}}cout<<ans<<'\n';}return 0;
}//分讨(较慢) 

暴搜:

听说或许可以构造数据 \(hack\) 掉?

但目前看来的确是最优解无疑了。

我们分别枚举 \(a,b\) 串的回文中心(记得特判一下回文串长度为偶数的情况呀),然后跟上面的 \(dp\) 转移相似,分别向左右暴搜就行了。

复杂度为 \(O(能过)\)(其实是我不会算😛)

代码:

$code$
#include<iostream>
using namespace std;
int T,m,n,ans;
string a,b;
inline void dfs(int la,int ra,int lb,int rb,int len){ans=max(ans,len);if(la>=1&&ra<=n&&a[la]==a[ra]) dfs(la-1,ra+1,lb,rb,len+2);if(la>=1&&rb<=m&&a[la]==b[rb]) dfs(la-1,ra,lb,rb+1,len+2);if(lb>=1&&ra<=n&&b[lb]==a[ra]) dfs(la,ra+1,lb-1,rb,len+2);if(lb>=1&&rb<=m&&b[lb]==b[rb]) dfs(la,ra,lb-1,rb+1,len+2);}
int main(){
//	freopen("string.in","r",stdin);
//	freopen("string.out","w",stdout);ios::sync_with_stdio(false);cin>>T;while(T--){ans=0;cin>>a>>b;a=' '+a;b=' '+b;n=a.size()-1;m=b.size()-1;for(int i=1;i<=n+1;i++){for(int j=1;j<=m+1;j++){dfs(i-1,i,j-1,j,0);if(i!=n+1) dfs(i-1,i+1,j-1,j,1);if(j!=m+1) dfs(i-1,i,j-1,j+1,1);//回文长度为偶数 }}cout<<ans<<'\n';}return 0;
}//暴搜(最快) 

一组 \(hack\) 数据

T2:数排列(perm)

思路:

嘿,有个 \(O(n^3)\) 的做法没听,当时光顾着笑(一些不明事物)了。这里只提供 \(O(n^2)\) 的做法。

我们设 \(f_{i,j}\) 表示数字 \(i\) 放到 \(j\) 的位置上的合法方案数,然后再前/后缀和优化一下撒~~

对于一个数 \(i\) ,若 \(s_i=1\) ,则我们设 \(f_{i,j}\) 表示 \(i\) 放在前 \(j\) 个位置的方案数 \(dp_{i,j}=\sum_{j=1}^{i} dp_{i-1,j}\)

代码:

$code$
#include<iostream>
using namespace std;
const int N=2025,mod=1e9+7;
int n,s[N],f[N][N],ans;
int main(){freopen("perm.in","r",stdin);freopen("perm.out","w",stdout);ios::sync_with_stdio(false);cin>>n;f[0][1]=1;for(int i=1;i<n;i++) cin>>s[i];for(int i=1;i<n;i++){if(s[i]==1) for(int j=2;j<=i+1;j++) f[i][j]=(f[i][j-1]+f[i-1][j-1])%mod;else for(int j=i;j>=1;j--) f[i][j]=(f[i][j+1]+f[i-1][j])%mod;}for(int i=1;i<=n;i++) ans=(ans+f[n-1][i])%mod;cout<<ans<<'\n';return 0;
}//O(n^2)

T3:树上的背包(knapsack)

思路:

这里提供根号分治和折半搜索两种思路。

折半搜索:

代码:

$code$
#include<iostream>
#include<algorithm>
#include<cstring>
#define int long long
using namespace std;
const int N=1e5+5;
int n,Q,x,L,cnt,tot1,tot2,ans,v[N],w[N],vl[N],wei[N];
struct flower{int val,weight;bool operator<(const flower &css)const{if(weight!=css.weight) return weight<css.weight;else return val<css.val;}
}a[N],s1[N],s2[N];
inline void dfs1(int pos,int weight,int val){if(weight>L) return ;if(pos==cnt/2+1){s1[++tot1]={val,weight};return ;}dfs1(pos+1,weight,val);dfs1(pos+1,weight+a[pos].weight,val+a[pos].val);
}
inline void dfs2(int pos,int weight,int val){if(weight>L) return ;if(pos==cnt+1){s2[++tot2]={val,weight};return ;}dfs2(pos+1,weight,val);dfs2(pos+1,weight+a[pos].weight,val+a[pos].val);
}
signed main(){freopen("knapsack.in","r",stdin);freopen("knapsack.out","w",stdout);ios::sync_with_stdio(false);cin>>n;for(int i=1;i<=n;i++) cin>>v[i]>>w[i];cin>>Q;while(Q--){tot1=tot2=ans=cnt=0;cin>>x>>L;a[++cnt]={0,0};while(x){a[++cnt]=(flower){v[x],w[x]};x/=2;}dfs1(1,0,0);dfs2(cnt/2+1,0,0);sort(s1+1,s1+tot1+1);sort(s2+1,s2+tot2+1);for(int i=1;i<=tot2;i++) s2[i].val=max(s2[i].val,s2[i-1].val);for(int i=1,j=tot2;i<=tot1;i++){while(j&&s2[j].weight+s1[i].weight>L) j--;if(s1[i].weight+s2[j].weight<=L) ans=max(ans,s1[i].val+s2[j].val);}cout<<ans<<'\n';}return 0;
}//折半搜 (慢) 
/*
3
1 2
2 3
3 4
3
1 1
2 5
3 515
123 119
129 120
132 112
126 109
118 103
115 109
102 100
130 120
105 105
132 115
104 102
107 107
127 116
121 104
121 115
8
8 234
9 244
10 226
11 227
12 240
13 237
14 206
15 227*/

根号分治:

代码:

$code$
#include<iostream>
#include<cstring>
using namespace std;
const int N=1e5+5,maxn=511;
int n,x,l,Q,dp[520][N];
struct flower{int v,w;
}a[N];
inline int work(int x,int l){if(l<0) return -1e9;if(x<=maxn) return dp[x][l];return max(work(x>>1,l),work(x>>1,l-a[x].w)+a[x].v);
}
int main(){
//	freopen("knapsack.in","r",stdin);
//	freopen("knapsack.out","w",stdout);ios::sync_with_stdio(false);cin>>n;for(int i=1;i<=n;i++) cin>>a[i].v>>a[i].w;for(int i=1;i<=min(maxn,n);i++){if(i>>1) memcpy(dp[i],dp[i>>1],sizeof(dp[i]));for(int j=N-5;j>=a[i].w;j--){dp[i][j]=max(dp[i][j],dp[i][j-a[i].w]+a[i].v);}}cin>>Q;while(Q--){cin>>x>>l;cout<<work(x,l)<<'\n';}return 0;
}

T2,T3未完...

后言:

感谢gyh提醒。

祝阿联生日快乐呀~~

http://www.jsqmd.com/news/21684/

相关文章:

  • Google Skills免费开放啦
  • ABP - 缓存(Caching)[IDistributedCache、ICacheManager、ICacheKeyNormalizer、[Cache]、[CacheInvalidate]]
  • 好想成为人类啊——2025 . 10 . 24
  • 10 24(+第14场补题)
  • 详细介绍:C++ 位运算 高频面试考点 力扣 268. 丢失的数字 题解 每日一题
  • 详细介绍:第十六届蓝桥杯软件赛C组省赛C++题解(京津冀)
  • 《打造自己的 DeepSeek》第 1 期:为什么要打造自己的 DeepSeek?
  • ret2text
  • ABP - 异常处理(Exception Handling)[AbpExceptionFilter、UserFriendlyException、IExceptionSubscriber]
  • 2025年沸腾干燥机厂家权威推荐榜单:专业直销与高效节能技术深度解析,提供优质沸腾干燥设备及定制方案
  • CF Round 1046(#2135) 总结
  • 重组蛋白表达的几种类型介绍
  • Luogu P5479 [BJOI2015] 隐身术 题解 [ 紫 ] [ 多维 DP ] [ 交换维度 ] [ 后缀数组 ] [ 哈希 ]
  • 2025年10月23日
  • 大象《Thinking in Projects》读书笔记2
  • 06_DNS解析:从域名到IP地址
  • ABP - 接口授权 [Authorize、AllowAnonymous、IPermissionChecker]
  • 日总结 17
  • 杂题选做-3
  • 10.24每日总结
  • 利用Eval Villain挖掘CSPT漏洞的完整指南
  • Button按钮插入图片后仍有白色边框的解决办法
  • Unity静态资源优化
  • 【Java】Spring @Transactional 事务失效:9大经典『陷阱』及终极解决方案
  • 【模板】动态 dp 学习笔记(树剖版)
  • ABP - JWT 鉴权(JWT Authentication)[AbpJwtBearerModule、JwtBearerOptions]
  • 软考四
  • CSP-S2022
  • Hugo主题定制速查手册
  • 10/24