QOJ.ac

QOJ

ID题目提交者结果用时内存语言文件大小提交时间测评时间
#489130#8819. CNOI KnowledgeFffooooTL 0ms0kbC++142.9kb2024-07-24 18:27:162024-07-24 18:27:16

Judging History

你现在查看的是最新测评结果

  • [2024-07-24 18:27:16]
  • 评测
  • 测评结果:TL
  • 用时:0ms
  • 内存:0kb
  • [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

output:


result: