12月就做过了,突然发现没发过题解
第一种方法是二分+哈希
首先 ∣ A ∣ + ∣ B ∣ ∈ [ 1 , ⌈ n k ⌉ ] |A|+|B| \in [1,\left \lceil \frac{n}{k} \right \rceil] ∣A∣+∣B∣∈[1,⌈kn⌉],这个很显然
设 i = ∣ A ∣ + ∣ B ∣ i=|A|+|B| i=∣A∣+∣B∣
那么可以二分 k ∗ i − B k*i-B k∗i−B,用差分维护
这个很显然就不说了
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std ;
#define rep(i, a, b) for (int (i) = (a); (i) <= (b); (i)++)
#define Rep(i, a, b) for (int (i) = (a) - 1; (i) < (b); (i)++)
#define REP(i, a, b) for (int (i) = (a); (i) >= (b); (i)--)
#define clr(a) memset(a, 0, sizeof(a))
#define Sort(a, len, cmp) sort(a + 1, a + len + 1, cmp)
#define ass(a, sum) memset(a, sum, sizeof(a))
#define ls ((rt) << 1)
#define rs ((rt) << 1 | 1)
#define lowbit(x) (x & -x)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define endl '\n'
#define ENDL cout << endl
#define SZ(x) ((int)x.size())
typedef long long ll ;
typedef unsigned long long ull ;
typedef vector <int> vi ;
typedef pair <int, int> pii ;
typedef pair <ll, ll> pll ;
typedef map <int, int> mii ;
typedef map <string, int> msi ;
typedef map <ll, ll> mll ;
const int N = 1000010 ;
const double eps = 1e-8 ;
const int iinf = INT_MAX ;
const ll linf = 2e18 ;
const double dinf = 1e30 ;
const int MOD = 1000000007 ;
const int x = 25625462 ;
const int y = 46835134 ;
inline int read(){
int X = 0, w = 0 ;
char ch = 0 ;
while (!isdigit(ch)) { w |= ch == '-' ; ch = getchar() ; }
while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar() ;
return w ? - X : X ;
}
void write(int x){
if (x < 0) putchar('-'), x = - x ;
if (x > 9) write(x / 10) ;
putchar(x % 10 + '0') ;
}
void print(int x) {
cout << x << endl ;
exit(0) ;
}
void PRINT(string x) {
cout << x << endl ;
exit(0) ;
}
void douout(double x){
printf("%lf\n", x + 0.0000000001) ;
}
string ans ;
char s[N] ;
ll hashx[N], hashy[N], powx[N], powy[N], a[N] ;
int n, k ;
bool check(int p, int q, int d) { // yes, double hash
ll hashp = hashx[p + d] - hashx[p] ;
if (hashp < 0) hashp += MOD ;
hashp = hashp * powx[q - p] % MOD ;
ll hashq = hashx[q + d] - hashx[q] ;
if (hashq < 0) hashq += MOD ;
if (hashp != hashq) return false ;
hashp = hashy[p + d] - hashy[p] ;
if (hashp < 0) hashp += MOD ;
hashp = hashp * powy[q - p] % MOD ;
hashq = hashy[q + d] - hashy[q] ;
if (hashq < 0) hashq += MOD ;
if (hashp != hashq) return false ;
return true ;
}
signed main(){
scanf("%d%d", &n, &k) ;
scanf("%s", s) ;
powx[0] = 1 ;
for (int i = 0; i < n; i++) powx[i + 1] = powx[i] * x % MOD ;
for (int i = 0; i < n; i++) hashx[i + 1] = (hashx[i] + (ll) (s[i] - 'a') * powx[i]) % MOD ;
powy[0] = 1 ;
for (int i = 0; i < n; i++) powy[i + 1] = powy[i] * y % MOD ;
for (int i = 0; i < n; i++) hashy[i + 1] = (hashy[i] + (ll) (s[i] - 'a') * powy[i]) % MOD ;
for (int i = 0; i <= n / k; i++) { // 下一个a的起点
int low = 0, high = n + 1 ;
while (low + 1 < high) {
int mid = (low + high) >> 1 ;
if (i + mid <= n && check(0, i, mid)) low = mid ;
else high = mid ;
}
int L = k * i ; int R = min(L + i, i + low) ;
if (L <= R) {
a[L]++ ;
a[R + 1]-- ;
}
}
for (int i = 0; i < n; i++) a[i + 1] += a[i] ;
for (int i = 0; i < n; i++) ans += ((a[i + 1] > 0) ? '1' : '0') ;
cout << ans << endl ;
}
/*
写代码时请注意:
1.是否要开Long Long?数组边界处理好了么?
2.实数精度有没有处理?
3.特殊情况处理好了么?
4.做一些总比不做好。
思考提醒:
1.最大值和最小值问题可不可以用二分答案?
2.有没有贪心策略?否则能不能dp?
*/
然后根据 R a d i o T r a n s i m i s s i o n \mathsf{Radio~Transimission} Radio Transimission,我们知道一个串的最小循环节 = n − n x t [ n ] =n-nxt[n] =n−nxt[n]
这个题目的 ∣ A ∣ + ∣ B ∣ |A|+|B| ∣A∣+∣B∣ 其实就相对应着循环节(但不一定是最小的)
设最小循环节为 m i n p d \mathsf{minpd} minpd
那么我们显然知道 ∣ A ∣ + ∣ B ∣ = m i n p d ∗ q |A|+|B|=\mathsf{minpd}*q ∣A∣+∣B∣=minpd∗q
加入枚举到长度 i i i
可以这么推导:
i = k ∗ ( ∣ A ∣ + ∣ B ∣ ) + ∣ A ∣ i=k*(|A|+|B|)+|A|\\ i=k∗(∣A∣+∣B∣)+∣A∣
∣ A ∣ |A| ∣A∣ 肯定小于等于 ∣ A ∣ + ∣ B ∣ |A|+|B| ∣A∣+∣B∣,所以原式等价于
k ∗ q ∗ m i n p d + [ 0 , q ∗ m i n p d ] = [ k ∗ q ∗ m i n p d , ( k + 1 ) ∗ q ∗ m i n p d ] k*q*\mathsf{minpd}+[0,q*\mathsf{minpd}]\\ =[k*q*\mathsf{minpd},(k+1)*q*\mathsf{minpd}] k∗q∗minpd+[0,q∗minpd]=[k∗q∗minpd,(k+1)∗q∗minpd]
答案显然是要求是否存在一个正整数 q q q
那么
q = [ i ( k + 1 ) m i n p d , i k m i n p d ] q=[\frac{i}{(k+1)\mathsf{minpd}},\frac{i}{k\mathsf{minpd}}] q=[(k+1)minpdi,kminpdi]
于是就搞定了
时间复杂度 O ( n ) O(n) O(n),很优秀
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std ;
//#define int long long
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
#define per(i, a, b) for (int i = (a); i >= (b); i--)
#define loop(s, v, it) for (s::iterator it = v.begin(); it != v.end(); it++)
#define cont(i, x) for (int i = head[x]; i; i = e[i].nxt)
#define clr(a) memset(a, 0, sizeof(a))
#define ass(a, sum) memset(a, sum, sizeof(a))
#define lowbit(x) (x & -x)
#define all(x) x.begin(), x.end()
#define ub upper_bound
#define lb lower_bound
#define pq priority_queue
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define iv inline void
#define enter cout << endl
#define siz(x) ((int)x.size())
#define file(s) freopen(s".in", "r", stdin), freopen(s."out", "w", stdout)
typedef long long ll ;
typedef unsigned long long ull ;
typedef pair <int, int> pii ;
typedef vector <int> vi ;
typedef vector <pii> vii ;
typedef queue <int> qi ;
typedef queue <pii> qii ;
typedef set <int> si ;
typedef map <int, int> mii ;
typedef map <string, int> msi ;
const int N = 1000010 ;
const int INF = 0x3f3f3f3f ;
const int iinf = 1 << 30 ;
const ll linf = 2e18 ;
const int MOD = 1000000007 ;
const double eps = 1e-7 ;
void print(int x) { cout << x << endl ; exit(0) ; }
void PRINT(string x) { cout << x << endl ; exit(0) ; }
void douout(double x){ printf("%lf\n", x + 0.0000000001) ; }
int nxt[N] ;
char s[N] ;
int n, k ;
void init() {
nxt[1] = 0 ;
for (int i = 2, j = 0; i <= n; i++) {
while (j && s[j + 1] != s[i]) j = nxt[j] ;
if (s[j + 1] == s[i]) j ++ ;
nxt[i] = j ;
}
}
int ok(int x) {
int len = x - nxt[x] ;
int l = ((x - 1) / len) / (k + 1) + 1, r = (x / len) / k ;
return l <= r ;
}
signed main(){
scanf("%d%d", &n, &k) ; scanf("%s", s + 1) ;
init() ;
rep(i, 1, n) cout << ok(i) ;
enter ;
return 0 ;
}
/*
写代码时请注意:
1.ll?数组大小,边界?数据范围?
2.精度?
3.特判?
4.至少做一些
思考提醒:
1.最大值最小->二分?
2.可以贪心么?不行dp可以么
3.可以优化么
4.维护区间用什么数据结构?
5.统计方案是用dp?模了么?
6.逆向思维?
*/
还有倍增 + k m p +kmp +kmp 的,多加一个 l o g log log,不怎么优秀,在这就不说了