AT_abc343_g [ABC343G] Compress Strings 题解
唐题。
考虑瞎状压, 表示末尾的字符串是 ,目前 这个二进制状态为 的位置已经是子串了。转移直接枚举上一个位置哈希。注意要把本身就在另一个字符串的子串中的删掉并去重。
#include <bits/stdc++.h>
using namespace std;
//#define int long long
using ll = long long;
const int N = 22, MOD = 1e9 + 9, HSMOD = 1610612741, HSMOD2 = 998244353; // Remember to change
int n, m, q, t, a[N];
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
long long qpow(long long a, long long b)
{
long long res = 1ll, base = a;
while (b)
{
if (b & 1ll) res = res * base % MOD;
base = base * base % MOD;
b >>= 1ll;
}
return res;
}
bool isprime(int x)
{
if (x == 1) return 0;
for (int i = 2; 1ll * i * i <= x; i++) if (x % i == 0) return 0;
return 1;
}
namespace FastIo
{
#define QUICKCIN ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
int read()
{
char ch = getchar();
int x = 0, f = 1;
while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
while (ch == '-')
{
f = -f;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
template<class T>
void write(T x)
{
if (x < 0)
{
putchar('-');
x = -x;
}
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template<class T>
void writeln(T x)
{
write(x);
putchar('\n');
}
}
template<typename T>
class Bit
{
public:
T lowbit(T x)
{
return x & -x;
}
T tr[N];
void add(T x, T y)
{
while (x < N)
{
tr[x] += y;
x += lowbit(x);
}
}
T query(T x)
{
T sum = 0;
while (x)
{
sum += tr[x];
x -= lowbit(x);
}
return sum;
}
};
int f[N][1<<21];
string s[N];
struct Two_Hash
{
long long hs1,hs2;
Two_Hash()=default;
Two_Hash(long long h1,long long h2):hs1(h1),hs2(h2){}
Two_Hash operator+(const Two_Hash x)
{
return Two_Hash((hs1+x.hs1)%MOD,(hs2+x.hs2)%HSMOD);
}
Two_Hash operator-(const Two_Hash x)
{
return Two_Hash((hs1-x.hs1+MOD)%MOD,(hs2-x.hs2+HSMOD)%HSMOD);
}
Two_Hash operator-(const long long x)
{
return Two_Hash((hs1-x+MOD)%MOD,(hs2-x+HSMOD)%HSMOD);
}
Two_Hash operator+(long long x)
{
return Two_Hash((hs1+x)%MOD,(hs2+x)%HSMOD);
}
Two_Hash operator*(const Two_Hash x)
{
return Two_Hash((hs1*x.hs1)%MOD,(hs2*x.hs2)%HSMOD);
}
Two_Hash operator*(const long long x)
{
return Two_Hash((hs1*x)%MOD,(hs2*x)%HSMOD);
}
bool operator==(const Two_Hash x)
{
return (hs1==x.hs1&&hs2==x.hs2);
}
};
const int M=5e5+5;
Two_Hash powe[M];
vector<Two_Hash> v1[N],v2[N];
int ans[N][N];
int getres(int x,int y)
{
int cnt=0;
for(int i=0;i<min(s[x].size(),s[y].size());i++)
{
if(v1[y][i]==v2[x][i]) cnt=i+1;
}
for(int i=0;i+s[y].size()-1<s[x].size();i++)
{
Two_Hash rr=v1[x][i+s[y].size()-1]-(i?v1[x][i-1]:Two_Hash(0,0))*powe[s[y].size()];
//cout<<"!!!!!: " <<rr.hs1<<" "<<rr.hs2<<"\n";
if(rr==v1[y][s[y].size()-1])
{
cnt=s[y].size();
}
}
return cnt;
}
vector<string> vecs;
int main()
{
ios::sync_with_stdio(0), cin.tie(nullptr), cout.tie(nullptr);
memset(f,0x3f,sizeof f);
cin>>n;
f[0][0]=0;
powe[0]=Two_Hash(1,1);
for(int i=1;i<M;i++) powe[i]=powe[i-1]*26;
set<string> ss;
for(int i=1;i<=n;i++)
{
cin>>s[i];
ss.insert(s[i]);
}
sort(s+1,s+n+1);
n=unique(s+1,s+n+1)-s;
if(ss.size()==1)
{
cout<<s[1].size()<<"\n";
return 0;
}
for(int i=1;i<=n;i++)
{
v1[i].clear(),v2[i].clear();
auto g=Two_Hash(0,0);
for(auto&j:s[i])
{
g=g*26+(j-'a'+1);
v1[i].emplace_back(g);
}
reverse(s[i].begin(),s[i].end());
g=Two_Hash(0,0);
Two_Hash nw=Two_Hash(1ll,1ll);
for(auto&j:s[i])
{
g=Two_Hash(j-'a'+1,j-'a'+1)*nw+g;
nw=nw*26;
v2[i].emplace_back(g);
}
reverse(s[i].begin(),s[i].end());
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++) ans[i][j]=getres(i,j);
}
for(int i=1;i<=n;i++)
{
bool f=1;
for(int j=1;j<=n;j++)
{
if(ans[j][i]==s[i].size()&&i!=j)
{
f=0;
}
}
if(f) vecs.emplace_back(s[i]);
}
n=vecs.size();
for(int i=1;i<=n;i++)
{
v1[i].clear(),v2[i].clear();
s[i]=vecs[i-1];
auto g=Two_Hash(0,0);
for(auto&j:s[i])
{
g=g*26+(j-'a'+1);
v1[i].emplace_back(g);
}
reverse(s[i].begin(),s[i].end());
g=Two_Hash(0,0);
Two_Hash nw=Two_Hash(1ll,1ll);
for(auto&j:s[i])
{
g=Two_Hash(j-'a'+1,j-'a'+1)*nw+g;
nw=nw*26;
v2[i].emplace_back(g);
}
reverse(s[i].begin(),s[i].end());
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++) ans[i][j]=getres(i,j);
}
for(int j=1;j<(1<<n);j++)
{
for(int i=1;i<=n;i++)
{
if(!((j>>(i-1))&1)) continue;
if(__builtin_popcount(j)==1)
{
f[i][j]=s[i].size();
}
else
{
for(int k=1;k<=n;k++)
{
if(k==i||((!((j>>(k-1))&1)))) continue;
f[i][j]=min(f[i][j],f[k][j-(1<<(i-1))]+(int)s[i].size()-ans[k][i]);
}
}
//cout<<"???????: "<<f[2][1]<<"\n";
}
}
int ans=(int)1e9;
for(int i=1;i<=n;i++) ans=min(ans,f[i][(1<<n)-1]);
cout<<ans<<"\n";
return 0;
}