字符串杂杂杂杂杂杂题
[CF1310C] Au Pont Rouge
首先,肯定要将所有的代价给弄出来,若先不管划分段数的限制,那么所有代价就是
那么字串的数量也就是
既然答案要求一个准确的字符串,所以考虑二分答案,首先对所有的代价进行排序(
对于当前二分的字符串
复杂度是
后面这个
对于字符串
,设 若
,则对于 的每个结尾处 的前缀,其字典序都大于 否则,
的所有前缀的字典序都小于
然后,距离做掉
这时,就又可以上
设
当
否则,就不存在
然后,就完了
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e3+5;
int n,m,lcp[N][N],l,r,mid,cnt;
ll k;
char s[N];
struct fk{
int l,r;
}a[N*N];
bool cmp(fk a,fk b){
int t=lcp[a.l][b.l];
if(t>=a.r-a.l+1||t>=b.r-b.l+1) return a.r-a.l+1<b.r-b.l+1;
return s[a.l+t]<s[b.l+t];
}
ll dp[N][N],sum[N][N];
bool check(int now){
memset(dp,0,sizeof(dp)),memset(sum,0,sizeof(sum));
sum[n+1][0]=1;
for(int i=n;i;--i){
int t=min(a[now].r-a[now].l+1,lcp[i][a[now].l]);
if(t==a[now].r-a[now].l+1||s[a[now].l+t]<s[i+t]) for(int j=1;j<=m;++j) dp[i][j]=sum[i+t+1][j-1];
for(int j=0;j<=m;++j) sum[i][j]=min(sum[i+1][j]+dp[i][j],k);
}
return dp[1][m]>=k;
}
int main(){
scanf("%d%d%lld",&n,&m,&k);
getchar(); for(int i=1;i<=n;++i) scanf("%c",&s[i]);
for(int i=n;i;--i)
for(int j=n;j;--j){
if(s[i]==s[j]) lcp[i][j]=lcp[i+1][j+1]+1;
if(j>=i) a[++cnt]=fk{i,j};
}
sort(a+1,a+cnt+1,cmp);
l=1,r=cnt;
while(l<=r){
mid=l+r>>1;
if(check(mid)) l=mid+1;
else r=mid-1;
}
for(int i=a[l].l;i<=a[l].r;++i) printf("%c",s[i]);
return 0;
}
[CF1701E] Text Editor
可以将
一段为从左往右删(可为空),一段为不删,一段为从右向左删(可为空)
那么操作的整体流程就是:从右向左删,遇到不删的区域,跳到左边去,然后从左往右删,遇到不删的区域,结束
根据这个方法,可以先定义出一个三位dp
然后就是因为
#include<bits/stdc++.h>
using namespace std;
const int N=5e3+5,INF=1061109567;
int n,m;
int dp[N][2][3],now;
char s[N],t[N];
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
getchar(); for(int i=1;i<=n;++i) scanf("%c",&s[i]);
getchar(); for(int i=1;i<=m;++i) scanf("%c",&t[i]);
if(m>n){ printf("-1\n"); continue; }
memset(dp,0x3f,sizeof(dp));
now=0,dp[0][0][0]=1,dp[0][0][1]=0;
for(int j=1;j<=n;++j){
now^=1;
dp[0][now][0]=j*2+1,dp[0][now][1]=0,dp[0][now][2]=j;
for(int i=1;i<=m;++i){
dp[i][now][0]=dp[i][now][1]=dp[i][now][2]=INF;
if(i<=j){
if(t[i]==s[j]){
dp[i][now][0]=dp[i-1][now^1][0]+1,dp[i][now][2]=dp[i-1][now^1][2]+1;
if(t[i-1]==s[j-1]) dp[i][now][1]=dp[i-1][now^1][1];
dp[i][now][1]=min(dp[i][now][1],dp[i-1][now^1][0]);
}
dp[i][now][0]=min(dp[i][now][0],dp[i][now^1][0]+2);
dp[i][now][2]=min(dp[i][now][2],min(dp[i][now^1][1]+1,dp[i][now^1][2]+1));
}
// cout<<i<<" "<<j<<" --- "<<dp[i][now][0]<<" "<<dp[i][now][1]<<" "<<dp[i][now][2]<<endl;
}
}
if(min({dp[m][now][0],dp[m][now][1],dp[m][now][2]})>=INF) printf("-1\n");
else printf("%d\n",min({dp[m][now][0],dp[m][now][1],dp[m][now][2]}));
}
return 0;
}
[CF150D] Mission Impassable
看到
设
然后,解决
而对于所有的区间,最后一步一定是删掉一个长度为
也可以算上,主要是如果算上了代码里要写很多个
,太麻烦了
如果
如果一起删,且分别为区间的两端
那么
然后答案就是
#include<bits/stdc++.h>
using namespace std;
const int N=155,INF=1e9;
int n,a[N],g[N][N][N],f[N][N],dp[N][N],ans;
char c[N];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&a[i]),a[i]=a[i]==-1?-INF:a[i];
getchar(); for(int i=1;i<=n;++i) scanf("%c",&c[i]);
memset(f,-0x3f3f3f3f,sizeof(f)),memset(g,-0x3f3f3f3f,sizeof(g));
for(int i=1;i<=n+1;++i) f[i][i-1]=0;
for(int len=1;len<=n;++len)
for(int l=1,r;l+len-1<=n;++l){
r=l+len-1,f[l][r]=-INF,g[l][r][0]=-INF,g[r][l][0]=-INF;
for(int k=1;k<=len;++k){
if(c[l]==c[r]){
if(k==1) g[l][r][k]=max(f[l+1][r],f[l][r-1]);
else if(k==2) g[l][r][k]=max(g[l][r][k],f[l+1][r-1]);
else g[l][r][k]=max(g[l][r][k],g[l+1][r-1][k-2]);
}
for(int p=l;p<r;++p) g[l][r][k]=max(g[l][r][k],max(g[l][p][k]+f[p+1][r],f[l][p]+g[p+1][r][k]));
f[l][r]=max(f[l][r],g[l][r][k]+a[k]);
}
}
for(int len=1;len<=n;++len)
for(int l=1,r;l+len-1<=n;++l){
r=l+len-1,dp[l][r]=max(0,f[l][r]);
for(int k=l;k<r;++k) dp[l][r]=max(dp[l][r],dp[l][k]+dp[k+1][r]);
}
printf("%d",max(dp[1][n],0));
return 0;
}
[SNOI2019]字符串
比较简单啊,找规律
考虑字符串
比较删除第一个
a
b
可与发现,若删除字符
所以,可以将原字符
若
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,tot,s[N],ans[N],now,head[N],nxt[N];
char a[N];
int main(){
scanf("%d",&n);
getchar();
for(int i=1,t;i<=n;++i){
scanf("%c",&t);
if(t!=a[tot]) a[++tot]=t,head[tot]=i;
else nxt[i-1]=i;
}
for(int i=1;i<tot;++i){
// cout<<i<<" "<<a[i]<<endl;
s[i]+=now;
if(a[i]-'a'<a[i+1]-'a') s[i]+=tot-i;
else ++now;
ans[s[i]]=i;
}
ans[now]=tot;
for(int i=0;i<tot;++i) for(int j=head[ans[i]];j;j=nxt[j]) printf("%d ",j);
return 0;
}
[CF1422E] Minlexes
对于题目进行一个解释:
aa
设
若
否则,可以选择
当
当
若
若
否则,不删
然后就是
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int len,coiled[N],lenn[N];
char dif[N];
string s,f[N];
string str(char a){
string ans; ans=a;
return ans;
}
void delet(string &s,int pos){
string s1(begin(s),begin(s)+5),s2(end(s)-2,end(s));
s=s1+s2;
}
int main(){
cin>>s;
len=s.size();
f[len-1]+=s[len-1],lenn[len-1]=1,dif[len-1]='?';
for(int i=len-2;i>-1;--i){
if(s[i]!=s[i+1]){
f[i]=s[i]+f[i+1],lenn[i]=lenn[i+1]+1;
if(s[i]!=f[i+1][0]) dif[i]=f[i+1][0];
else dif[i]=dif[i+1];
}else{
if(!lenn[i+2]){ dif[i]='?'; continue; }
if(s[i]!=f[i+2][0]){
if(s[i]>f[i+2][0]) f[i]=f[i+2],lenn[i]=lenn[i+2],dif[i]=dif[i+2];
else f[i]=str(s[i])+str(s[i])+f[i+2],lenn[i]=lenn[i+2]+2,dif[i]=f[i+2][0];
}else{
if(dif[i+2]>f[i+2][0]) f[i]=str(s[i])+str(s[i])+f[i+2],lenn[i]=lenn[i+2]+2;
else f[i]=f[i+2],lenn[i]=lenn[i+2];
dif[i]=dif[i+2];
}
}
if(f[i].size()>10) delet(f[i],i);
}
for(int i=0;i<len;++i){
printf("%d ",lenn[i]);
if(lenn[i]<=10) cout<<f[i]<<endl;
else{
for(int j=0;j<5;++j) printf("%c",f[i][j]);
printf("...");
for(int j=f[i].size()-2;j<f[i].size();++j) printf("%c",f[i][j]);
printf("\n");
}
}
return 0;
}
[CF1562E] Rescue Niwen!
自己简单搞个字符串模一模,就可以发现排好序后的序列呈一个分成
一个段内的形式大概如下:
也就是说,若选了该段中的第
这启示我们,若答案的最长序列中以第
还有,若可以由第
因为第
段中的第 个子串已经小于第i段的第 个子串了,所以无论在第 个子串后面加多少个字符,都会小于第 个子串
所以,上dp
#include<bits/stdc++.h>
using namespace std;
const int N=5e3+5;
int n,dp[N],ans,lcp[N][N];
char s[N];
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
getchar(); scanf("%s",s+1);
for(int i=n;i;--i) for(int j=n;j;--j) lcp[i][n+1]=lcp[n+1][i]=0,lcp[i][j]=((s[i]==s[j])?lcp[i+1][j+1]+1:0);
ans=0;
for(int i=1;i<=n;++i){
dp[i]=n-i+1;
for(int j=1;j<i;++j) if(lcp[i][j]<n-i+1&&s[i+lcp[i][j]]>s[j+lcp[i][j]]) dp[i]=max(dp[i],dp[j]+n-i+1-lcp[i][j]);
ans=max(ans,dp[i]);
}
printf("%d\n",ans);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)