TIOJ 2070:Special Judge
TIOJ 2070:Special Judge
題目大意:給一個字串 X,問由 ‘a′∼‘a′+k−1 組成長度為 k 字串的所有子集是否皆為 X 的子序列。子集就是刪任意個字元,任意排列出來,子序列就是可以刪任意個字元,保持相對位置。
解法:O(26×|X|+k×2k) 的作法。可以用一個陣列 suf[26][|X|+2],suf[j][i] 代表現在的字母為 j,在字串中的位置為 i,在 i 以後第一個出現 j 的位置。之後由 0 枚舉到 2k−1,假設現在數字為 i,i 的二進制裡有 1 的位元,則代表此字串可以找出這些位元所有排列,last[i] 代表這些排列裡最後一個字元出現位置的最大值,之後要向還沒找到的字母拓展,可以找到這些字母位置大於 last[i],又最接近 last[i] 的位置,也就是 suf[j][last[i]+1],如果找不到,代表找不到這種排列,那就輸出 No,否則將 last[i+2j] 調為自己與 suf[j][last[i]+1] 的最大值。至於如何拿到 Topcoder,可以知道這題跟 "位元" 很有關係,可以朝 "位元" 的方向去想。
Code:
#pragma GCC optimize("O3")
#include <bits/stdc++.h>
using namespace std;
#define FOR(x,a,b) for(int x=a;x<=b;x++)
#define pb emplace_back
const int INF = 1e9;
int last[1 << 20];
void solve() {
int k, n;
string s;
cin >> k >> s;
n = s.size(), s = " " + s;
int suf[26][n + 2];
FOR (i, 0, 25) suf[i][n + 1] = INF;
for (int i = n; i >= 1; i--) {
FOR (j, 0, 25) suf[j][i] = suf[j][i + 1];
suf[s[i] - 'a'][i] = i;
}
fill (last, last + (1 << k), 0);
for (int i = 0, I = 1 << k; i < I; i++) {
for (int j = 0; j < k; j++) {
if ( (i >> j) & 1)
continue;
int m = i ^ (1 << j), p = suf[j][last[i] + 1];
if (p == INF) {
cout << "No\n";
return;
}
last[m] = max (last[m], p);
}
}
cout << "Yes\n";
}
int main() {
ios::sync_with_stdio (false), cin.tie (0);
int tt;
cin >> tt;
while (tt--)
solve();
}
我的分享就到這裡結束了,如果喜歡我的 Blog,歡迎追蹤!
留言
張貼留言