E - Stringforces
Title Description
Give you a include? And before k k k lowercase strings s s s. You need to put each? Replace with previous k k One of the k lowercase letters that makes the string s s s v a l val val max.
definition
f
i
f_i
fi represents a string
s
s
The longest quanyoudi in s
i
i
The length of a substring of i letters,
v
a
l
=
min
1
≤
i
≤
k
f
i
val=\min_{1\le i\le k}f_i
val=1≤i≤kminfi
Data range and tips
1 ≤ n ≤ 2 ⋅ 1 0 5 , 1 ≤ k ≤ 17 1\le n\le 2\cdot 10^5,1\le k\le 17 1≤n≤2⋅105,1≤k≤17 .
preface
This problem thought of dichotomy and shape pressure and ran to do F. unexpectedly, he slipped past the front door of the positive solution.
thinking
Take a look at this question k ≤ 17 k\le 17 k ≤ 17, immediately think of state compression.
Because the length of the substring is uncertain, and there are fetches at the same time max \max max sum min \min min, it's not easy to think directly, but obviously if v a l val val can't get it a a a. Then you can't get it a + 1 a+1 a+1 satisfies monotonicity, so consider the dichotomous answer.
After two answers, v a l val val is sure, that is, the smallest f i f_i fi , determined, which is equivalent to meeting all requirements f i f_i fi , must be greater than or equal to v a l val val . f i f_i fi is greater than or equal to v a l val val if and only if s s There is a with length in s v a l val Quan Youdi of val i i i characters, so we turn the problem into each character i i i find a length of v a l val The interval of val, which satisfies that all characters in the interval can be the second i i i characters, and this k k k intervals do not intersect each other.
Then you can
c
h
e
c
k
check
check internal pressure DP:
d
p
[
x
]
dp[x]
dp[x] indicates that the status of the character type that has solved the demand is
x
x
x, the minimum value of the rightmost endpoint between the selected areas. Then take a
O
(
n
k
)
O(nk)
O(nk) time preprocessing
c
l
cl
cl array, where
c
l
[
i
]
[
j
]
cl[i][j]
cl[i][j] indicates location
i
i
i back, can be the second
j
j
The left end point of the nearest interval selected by j characters, (let the character number start from 0) then transfer to
d
p
[
x
]
=
min
(
1
<
<
i
)
∈
x
c
l
[
d
p
[
x
−
(
1
<
<
i
)
]
+
1
]
[
i
]
+
v
a
l
−
1
dp[x]=\min_{(1<<i)\in x}cl[dp[x-(1<<i)]+1][i]+val-1
dp[x]=(1<<i)∈xmincl[dp[x−(1<<i)]+1][i]+val−1
The total transfer complexity is
O
(
k
⋅
2
k
)
O(k\cdot 2^k)
O(k ⋅ 2k), so the total complexity is
O
(
k
log
n
⋅
(
2
k
+
n
)
)
O(k\log n\cdot(2^k+n))
O(klogn⋅(2k+n)) .
There is no better way on CF, which is the fastest way. It is worth noting that I actually saw the complexity of up to on CF O ( k log n ⋅ 2 k ⋅ k 2 ⋅ log n ) O(k\log n\cdot 2^k\cdot \frac{k}{2}\cdot\log n) The AC code of O(klogn ⋅ 2k ⋅ 2k ⋅ logn) shows that the data of this problem is very friendly.
code
171ms rank1 code
#include<cstdio>//JZM yyds!!! #include<cstring> #include<iostream> #include<algorithm> #include<cmath> #include<vector> #include<queue> #include<stack> #include<ctime> #include<map> #define ll long long #define MAXN 200005 #define MAXM 1000005 #define uns unsigned #define INF 1e18 #define MOD 1000000007ll #define lowbit(x) ((x)&(-(x))) using namespace std; inline ll read(){ ll x=0;bool f=1;char s=getchar(); while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();} while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+s-'0',s=getchar(); return f?x:-x; } int n,k,num[20],cl[MAXN][20]; int dp[MAXN]; char s[MAXN]; inline bool check(int m){ for(int i=0;i<k;i++)num[i]=0; int tot=0; for(int j=0;j<k;j++)cl[n+1][j]=cl[n+2][j]=n+1; // printf("%d:\n",m); for(int i=n;i>0;i--){ for(int j=0;j<k;j++)cl[i][j]=cl[i+1][j]; if(s[i]!='?'){ int c=s[i]-'a'; num[c]++; if(num[c]==1)tot++; } if(i+m<=n&&s[i+m]!='?'){ int c=s[i+m]-'a'; num[c]--; if(num[c]==0)tot--; } // printf(" %d %d\n",i,tot); if(i+m>n+1)continue; if(tot==1){ for(int j=0;j<k;j++)if(num[j]>0)cl[i][j]=i; } else if(tot==0){ for(int j=0;j<k;j++)cl[i][j]=i; } } // for(int i=1;i<=n;i++)printf(" %d %d\n",cl[i][0],cl[i][1]); int lim=(1<<k); for(int s=1;s<lim;s++)dp[s]=n+1; dp[0]=0; for(int s=1;s<lim;s++) for(int i=0;i<k;i++) if((s>>i)&1){ int p=s^(1<<i); dp[s]=min(dp[s],cl[dp[p]+1][i]+m-1); } return dp[lim-1]<=n; } signed main() { n=read(),k=read(); scanf("%s",s+1); int l=0,r=n/k,mid; while(l<r){ mid=(l+r+1)>>1; if(check(mid))l=mid; else r=mid-1; } printf("%d\n",l); return 0; }