1326D2 - Prefix-Suffix Palindrome (Hard version)马拉车/哈希,I-秋游_状压dp+最短路

142 篇文章 1 订阅
92 篇文章 0 订阅

1326D2 - Prefix-Suffix Palindrome (Hard version) 马拉车/哈希

用双指针将两边的点缩进,也就是if(s[l]==s[r]) l++,r--,然后中间那一块将其分别求出前缀最大的回文串和后缀最大的回文串,然后比较一下输出一个最大的就可以,这个问题可以用马拉车解决

D2. Prefix-Suffix Palindrome (Hard version)-----------------------------------思维(马拉车)_AKone123456的博客-CSDN博客

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod=1e9+7;
const int N = 2e6+100;
int t,p[N],n,len,ans,f;
char s[N],str[N];
void init(int l,int r)
{
    int k=0;
    str[k++]='@';
    for(int i=l;i<=r;i++)
    {
        str[k++]='#';
        str[k++]=s[i];
    }
    str[k++]='#';
    len=k;
    str[k]='\0';
    ans=0;
    for(int i=1;i<=2*n;i++) p[i]=0;
}
void mlc(int l,int r)
{
    init(l,r);
    int mx=0,id=0;
    p[0]=0;
    for(int i=1;i<len;i++)
    {
        if(i<mx) p[i]=min(mx-i,p[2*id-i]);
        else p[i]=1;
        while(str[i-p[i]]==str[i+p[i]]) p[i]++;
        if(i+p[i]>mx)
        {
            mx=i+p[i];
            id=i;
        }
        if(p[i]==i)
        {
            if(ans<p[i])
            {
                ans=p[i]-1;
                f=1;
            }
        }
        if(p[i]+i==len)
        {
            if(ans<p[i])
            {
                ans=p[i]-1;
                f=2;
            }
        }
    }
}
signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    //cout<<(1LL<<61)<<endl;
    cin>>t;
    while(t--)
    {
        cin>>(s+1);
        n=strlen(s+1);
        int l=1,r=n;
        while(l<=r&&s[l]==s[r]) l++,r--;
        if(l>=r)
        {
            for(int i=1;i<=n;i++) cout<<s[i];
            cout<<endl;
            continue;
        }
        mlc(l,r);
        //cout<<l<<" "<<r<<endl;
        for(int i=1;i<=l-1;i++) cout<<s[i];
        if(f==1)
        {
            for(int i=l,j=1;j<=ans;i++,j++) cout<<s[i];
        }
        else 
        {
            for(int i=r-ans+1,j=1;j<=ans;j++,i++) cout<<s[i];
        }
        for(int i=r+1;i<=n;i++) cout<<s[i];
        cout<<endl;
    }
    system("pause");
    return 0;
}

字符串哈希的解法

Codeforces D1/D2. Prefix-Suffix Palindrome (字符串hash) /详解_江先生的故事的博客-CSDN博客

#include <bits/stdc++.h>
using namespace std;
#define int long long
//const int mod=1e9+7;
const int N = 2e6+100;
int base[2]={1333331,13331},mod[2]={1000000007,998244353};
int h[2][N],po[2][N],hs[2][N];
int t,n;
char s[N];
int getpre(int fg,int l,int r)
{
    return ((h[fg][r]-(h[fg][l-1]*po[fg][r-l+1]%mod[fg]))%mod[fg]+mod[fg])%mod[fg];
}
int getsuf(int fg,int l,int r)
{
    return ((hs[fg][l]-(hs[fg][r+1]*po[fg][r-l+1]%mod[fg]))%mod[fg]+mod[fg])%mod[fg]; 
}
signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    //cout<<(1LL<<61)<<endl;
    cin>>t;
    po[0][0]=po[1][0]=1;
    for(int i=1;i<=1000000;i++)
    {
        po[0][i]=po[0][i-1]*base[0]%mod[0];
        po[1][i]=po[1][i-1]*base[1]%mod[1];
    }
    while(t--)
    {
        cin>>(s+1);
        n=strlen(s+1);
        h[0][0]=h[1][0]=0;
        for(int i=1;i<=n;i++)
        {
            h[0][i]=(h[0][i-1]*base[0]%mod[0]+(s[i]-'a'+1))%mod[0];
            h[1][i]=(h[1][i-1]*base[1]%mod[1]+(s[i]-'a'+1))%mod[1];
        } 
        hs[0][n+1]=hs[1][n+1]=0;
        for(int i=n;i>=1;i--)
        {
            hs[0][i]=(hs[0][i+1]*base[0]%mod[0]+(s[i]-'a'+1))%mod[0];
            hs[1][i]=(hs[1][i+1]*base[1]%mod[1]+(s[i]-'a'+1))%mod[1];
        }
        int l=1,r=n;
        while(l<=r&&s[l]==s[r]) l++,r--;
        if(l>=r)
        {
            for(int i=1;i<=n;i++) cout<<s[i];
            cout<<endl;
            continue;
        }
        int ans=0,f=0;
        for(int i=l;i<=r;i++)
        {
            int x1=getpre(0,l,i),x2=getpre(1,l,i);
            int y1=getsuf(0,l,i),y2=getsuf(1,l,i);
            
            if(x1==y1&&x2==y2)
            {
                //cout<<x1<<" "<<y1<<" "<<x2<<" "<<y2<<" "<<l<<" "<<i<<endl;
                if(ans<i-l+1){f=1;ans=i-l+1;}
            }
        }
        for(int i=l;i<=r;i++)
        {
            int x1=getpre(0,i,r),x2=getpre(1,i,r);
            int y1=getsuf(0,i,r),y2=getsuf(1,i,r);
            if(x1==y1&&x2==y2)
            {
                //cout<<x1<<" "<<y1<<" "<<x2<<" "<<y2<<" "<<i<<" "<<r<<endl;
                if(ans<r-i+1){f=2;ans=r-i+1;}
            }
        }
        //out<<ans<<" "<<f<<endl;
        for(int i=1;i<=l-1;i++) cout<<s[i];
        
        if(f==1)
        {
            for(int i=l,j=1;j<=ans;i++,j++) cout<<s[i];
        }
        else 
        {
            for(int i=r-ans+1,j=1;j<=ans;j++,i++) cout<<s[i];
        }
        for(int i=r+1;i<=n;i++) cout<<s[i];
        cout<<endl;
    }
    system("pause");
    return 0;
}

I-秋游_状压dp+最短路

x最多不超过18,并且还要包括1这个点所以不超过19,1<<19不到1e6,而且是让求经过y个点的最小路径,一看就很想状压dp的典题,只不过是由x个点的排列变成了y个点的排列,直接在dp的过程中更新就行,两两的距离直接跑上x+1遍dij就可以

代码查看 (nowcoder.com)

#include <bits/stdc++.h>
using namespace std;
#define int long long
//const int mod=1e9+7;
const int N = 2e6+100;
int head[N],cnt;
struct Edge
{
    int next,to,dis;
}e[N];
void addedge(int from,int to,int w)
{
    e[++cnt].to=to;
    e[cnt].dis=w;
    e[cnt].next=head[from];
    head[from]=cnt;
}
struct node
{
    int id,dis;
    bool operator<(const node &a)const
    {
        return a.dis<dis;
    }
};
int vis[N],dist[N];
int n,x,y,f[600005][20],a[20],m;
map<pair<int,int>,int>mp;
void dij(int s)
{
    priority_queue<node>q;q.push(node{s,0});
    for(int i=1;i<=n;i++) vis[i]=0,dist[i]=1e18;
    dist[s]=0;
    while(!q.empty())
    {
        node u=q.top();q.pop();
        int now=u.id;
        if(vis[now]) continue;
        vis[now]=1;
        for(int i=head[now];i;i=e[i].next)
        {
            int j=e[i].to;
            if(dist[now]+e[i].dis<dist[j])
            {
                dist[j]=dist[now]+e[i].dis;
                q.push(node{j,dist[j]});
            }
        }
    }
    for(int i=1;i<=x;i++)
    if(!mp[{s,a[i]}]) mp[{s,a[i]}]=mp[{a[i],s}]=dist[a[i]];
    else mp[{s,a[i]}]=mp[{a[i],s}]=min(mp[{s,a[i]}],dist[a[i]]);
}
signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    //cout<<(1LL<<19)<<endl;
    cin>>n>>x>>y;
    a[1]=1;x++;
    for(int i=2;i<=x;i++) cin>>a[i];
    cin>>m;
    for(int i=1;i<=m;i++)
    {
        int u,v,w;
        cin>>u>>v>>w;
        addedge(u,v,w);
        addedge(v,u,w);
    }
    for(int i=1;i<=x;i++) dij(a[i]);
    for(int s=0;s<(1<<x);s++)
    for(int i=1;i<=x;i++)  f[s][i]=1e18;
    f[1][1]=0;
    int ans=1e18;
    for(int s=0;s<(1<<x);s++)
    {
        int tmp=__builtin_popcount(s);
        if(tmp-1>y) continue;
        for(int i=1;i<=x;i++)
        {
            if(((s>>i-1)&1)==0) continue;
            for(int j=1;j<=x;j++)
            {
                if(i==j||((s>>(j-1))&1)) continue;
                f[s|(1<<j-1)][j]=min(f[s|(1<<j-1)][j],f[s][i]+mp[{a[i],a[j]}]);
            }
            if(tmp-1==y) ans=min(ans,f[s][i]+mp[{a[i],1}]);
        }
    }
    cout<<ans<<endl;
    system("pause");
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

killer_queen4804

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值