题解:CF1789F Serval and Brain Power
神秘的通过了,记录一下。
思路
首先我想到了如果
然后剩下
分析发现只剩下
code
#include<bits/stdc++.h>
using namespace std;
namespace IO
{
template<typename T>
void read(T &_x){_x=0;int _f=1;char ch=getchar();while(!isdigit(ch)) _f=(ch=='-'?-1:_f),ch=getchar();while(isdigit(ch)) _x=_x*10+(ch^48),ch=getchar();_x*=_f;}
template<typename T,typename... Args>
void read(T &_x,Args&...others){Read(_x);Read(others...);}
const int BUF=20000000;char buf[BUF],to,stk[32];int plen;
#define pc(x) buf[plen++]=x
#define flush(); fwrite(buf,1,plen,stdout),plen=0;
template<typename T>inline void print(T x){if(!x){pc(48);return;}if(x<0) x=-x,pc('-');for(;x;x/=10) stk[++to]=48+x%10;while(to) pc(stk[to--]);}
}
using namespace IO;
const int N = 100,M = 26;
int n,a[N],b[N],cnt,x,y,z,nxt[N][30],f[N][N],g[N][N][N],ans,sum,o,O;
string s;
inline int solve(int len)
{
x = sum = 0;
while(1)
{
for(int i = 1;i <= len;i++)
{
x = nxt[x+1][b[i]];
if(x > n) return sum;
}
sum += len;
}
return sum;
}
signed main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
cin >> s; n = s.size(); s = ' '+s;
for(int i = 1;i <= n;i++) a[i] = s[i]-'a';
for(int i = 0;i < M;i++) nxt[n+1][i] = n+1;
for(int i = n;i >= 1;i--)
{
for(int j = 0;j < M;j++) nxt[i][j] = nxt[i+1][j];
nxt[i][a[i]] = i;
}
for(int r = 2;r <= n;r++)
{
for(int i = 1;i < r;i++)
for(int j = r;j <= n;j++)
f[i][j] = 0;
for(int l = 1;l <= r;l++)
if(a[l] == a[r])
f[l][r] = 2;
for(int i = 1;i < r;i++)
for(int j = r;j <= n;j++)
if(f[i][j])
for(int z = 0;z < 26;z++)
{
if(nxt[i+1][z] < r && nxt[j+1][z] <= n)
f[nxt[i+1][z]][nxt[j+1][z]] = max(f[nxt[i+1][z]][nxt[j+1][z]],f[i][j]+2);
}
for(int i = 1;i < r;i++)
for(int j = r;j <= n;j++)
ans = max(ans,f[i][j]);
}
for(int r = 2;r <= n;r++)
for(int m = r+1;m <= n;m++)
{
for(int i = 1;i < r;i++)
for(int j = r;j < m;j++)
for(int z = m;z <= n;z++)
g[i][j][z] = 0;
for(int l = 1;l <= r;l++)
if(a[l] == a[r] && a[r] == a[m]) g[l][r][m] = 3;
for(int i = 1;i < r;i++)
for(int j = r;j < m;j++)
for(int z = m;z <= n;z++)
if(g[i][j][z])
for(int k = 0;k < 26;k++)
{
if(nxt[i+1][k] < r && nxt[j+1][k] < m && nxt[z+1][k] <= n)
g[nxt[i+1][k]][nxt[j+1][k]][nxt[z+1][k]] = max(g[nxt[i+1][k]][nxt[j+1][k]][nxt[z+1][k]],g[i][j][z]+3);
}
for(int i = 1;i < r;i++)
for(int j = r;j < m;j++)
for(int z = m;z <= n;z++)
ans = max(ans,g[i][j][z]);
}
for(int i = 1;;i++)
{
O = (1<<min(n-i+1,16));
for(int j = 1;j < O;j++)
{
cnt = 0;
for(int z = 0;z < 16 && z+i <= n;z++)
if(((1<<z)&j)) b[++cnt] = a[z+i];
o = solve(cnt);
if(o >= cnt*2) ans = max(ans,o);
}
if(i+15 >= n) break;
}
print(ans); flush();
return 0;
}
/*
其实可以这样,f_{l,r,i,j}表示开始左右端点是(l,r),然后目前匹配到(i,j)了的最大长度是多少
首先是初值,显然可以就是a_l=a_r,那么f_{l,r,l,r}
枚举l,r然后g_{i,j}
然后转移就是枚举一个字符然后转移过去
复杂度,emm,当然系n^3*26的
注意到k%2可能等于1,这里只解决了k%2=0的
k==3可以暴力枚举三个点跑转移,复杂度也就n^6*26(跑不满,应该很小才对)
然后我们可以枚举集合了,注意到我们选的一段序列总有一段跨度不超过n/k,否则每个都大于那你长度不就超标了
考虑枚举i,然后状压16个位置看是否选,然后求出序列,我们显然贪心的看匹配出最大的就好了,复杂度2^16*n^2
*/