1326D2 - Prefix-Suffix Palindrome (Hard version) 马拉车/哈希
用双指针将两边的点缩进,也就是if(s[l]==s[r]) l++,r--,然后中间那一块将其分别求出前缀最大的回文串和后缀最大的回文串,然后比较一下输出一个最大的就可以,这个问题可以用马拉车解决
#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就可以
#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;
}