QOJ.ac
QOJ
ID | 题目 | 提交者 | 结果 | 用时 | 内存 | 语言 | 文件大小 | 提交时间 | 测评时间 |
---|---|---|---|---|---|---|---|---|---|
#489130 | #8819. CNOI Knowledge | Fffoooo | TL | 0ms | 0kb | C++14 | 2.9kb | 2024-07-24 18:27:16 | 2024-07-24 18:27:16 |
answer
#include<bits/stdc++.h>
using namespace std;
int mian(); int main() { return mian(); }
const int N = 1024;
int n, s[N];
int ASK(const int l, const int r) { printf("? %d %d\n", l, r); int x; scanf("%d", &x); return x; }
int Size, root, lat;
struct SAM {
int link, len;
int son[N];
}sam[N << 1];
vector<int> lison[N];
void init_SAM() {
Size = root = lat = 0;
sam[0].link = -1;
lison[0].clear();
memset(sam[0].son, 0, sizeof sam[0].son);
}
int new_t() {
int cur = ++Size;
sam[cur].link = sam[cur].len = 0;
lison[cur].clear();
memset(sam[cur].son, 0, sizeof sam[cur].son);
return cur;
}
void Insert(int c) {
int cur = new_t();
sam[cur].len = sam[lat].len + 1;
int p = lat;
while( p != -1 and !sam[p].son[c] ) sam[p].son[c] = cur, p = sam[p].link;
if( p == -1 ) sam[cur].link = 0;
else {
const int q = sam[p].son[c];
if( sam[q].len == sam[p].len + 1 ) sam[cur].link = q;
else {
const int nq = new_t();
sam[nq] = sam[q];
sam[nq].len = sam[p].len + 1;
while( p != -1 and sam[p].son[c] == q ) sam[p].son[c] = nq, p = sam[p].link;
sam[cur].link = sam[q].link = nq;
}
}
lat = cur;
}
int ask(const int l, const int r) {
init_SAM();
for(int i = l; i <= r; ++i) Insert(s[i]);
for(int i = 1; i <= Size; ++i) lison[ sam[i].link ].push_back(i);//, cout<<sam[i].link<<" ";; puts("");
queue<int> q; q.push(root);
int ans = 0;
while( !q.empty() ) {
const int u = q.front(); q.pop();
for(auto v : lison[u]) ans += sam[v].len - sam[u].len, q.push(v);
}
return ans;
}
int mian() {
scanf("%d", &n);
s[1] = 1;
int cnt_l = 1;
for(int i = 2; i <= n; ++i) {
int l = 1, r = i - 1, ans = i;
while( l <= r ) {
const int mid = (l + r) >> 1;
if( ASK( mid, i ) == ask( mid, i - 1 ) + ( i - mid + 1 ) ) r = mid - 1, ans = mid;
else l = mid + 1;
}
if( ans == 1 ) s[i] = ++cnt_l;
else s[i] = s[ans - 1];
}
putchar('!');
for(int i = 1; i <= n; ++i) printf(" %d", s[i]);
// for(int i = 1; i <= n; ++i) scanf("%d", &s[i]);
// int Q; scanf("%d", &Q);
// while(Q--){
// int l, r; cin>>l>>r;
// cout<<ask(l, r)<<endl;
// }
return 0;
} /*
5
1 3 4 1 3
4
1 2
1 2
1 3
1 4
有一个隐藏的字符串,每一次可以询问一个区间内的本质不同字串数量
在 $10^4$ 次内得到这个字符串,之只需输出一种与隐藏字符串形式相同的答案即可(因为可以对每个字符互相替换)
$n\le 10^3, |\sum|\le n$
$1s,1G$
考虑 $n\log n$ 次询问得到最终答案
假设当前位置是 $i$,那么如果 $i$ 是一个全新的字符,$(1,i-1)$ 必定刚好比 $(1,i)$ 少 $i$ 个不同子串(以 $i$ 结尾的)
那么直接二分,假设 $s_i$ 在最长的 $[l,i)$ 未出现,则 $s_i=s_{l-1}$
特判端点,每一次对于一个区间的最长本质不同子串直接暴力建 SAM,每个点的贡献就是 $len-len[fa]$ ,加起来即可
*/
詳細信息
Test #1:
score: 0
Time Limit Exceeded
input:
12